diff --git a/OpenMetaverse.GUI/MiniMap.cs b/OpenMetaverse.GUI/MiniMap.cs index 003a86f4..3cecd843 100644 --- a/OpenMetaverse.GUI/MiniMap.cs +++ b/OpenMetaverse.GUI/MiniMap.cs @@ -24,11 +24,12 @@ * POSSIBILITY OF SUCH DAMAGE. */ -using OpenMetaverse.Imaging; using System; using System.Collections.Generic; using System.Drawing; using System.Windows.Forms; +using OpenMetaverse.Imaging; +using OpenMetaverse.Assets; namespace OpenMetaverse.GUI { diff --git a/OpenMetaverse/AppearanceManager.cs b/OpenMetaverse/AppearanceManager.cs index 9da5a725..434a72ac 100644 --- a/OpenMetaverse/AppearanceManager.cs +++ b/OpenMetaverse/AppearanceManager.cs @@ -32,6 +32,7 @@ using System.IO; using OpenMetaverse; using OpenMetaverse.Packets; using OpenMetaverse.Imaging; +using OpenMetaverse.Assets; namespace OpenMetaverse { diff --git a/OpenMetaverse/AssetManager.cs b/OpenMetaverse/AssetManager.cs index 931fc710..7a97e9cd 100644 --- a/OpenMetaverse/AssetManager.cs +++ b/OpenMetaverse/AssetManager.cs @@ -30,6 +30,7 @@ using System.Threading; using System.IO; using OpenMetaverse; using OpenMetaverse.Packets; +using OpenMetaverse.Assets; namespace OpenMetaverse { diff --git a/OpenMetaverse/AssetTypes.cs b/OpenMetaverse/AssetTypes.cs deleted file mode 100644 index e3d727d5..00000000 --- a/OpenMetaverse/AssetTypes.cs +++ /dev/null @@ -1,784 +0,0 @@ -/* - * Copyright (c) 2007-2008, openmetaverse.org - * All rights reserved. - * - * - 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. - * - Neither the name of the openmetaverse.org 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 COPYRIGHT HOLDERS AND CONTRIBUTORS "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 COPYRIGHT OWNER OR 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 System; -using System.Text; -using System.Collections.Generic; -using OpenMetaverse.Imaging; - -namespace OpenMetaverse -{ - /// - /// - /// - [Flags] - public enum WearableType : byte - { - /// A shape - Shape = 0, - /// - Skin, - /// - Hair, - /// - Eyes, - /// - Shirt, - /// - Pants, - /// - Shoes, - /// - Socks, - /// - Jacket, - /// - Gloves, - /// - Undershirt, - /// - Underpants, - /// - Skirt, - /// - Invalid = 255 - }; - - /// - /// Base class for all Asset types - /// - public abstract class Asset - { - /// A byte array containing the raw asset data - public byte[] AssetData; - /// True if the asset it only stored on the server temporarily - public bool Temporary; - /// A unique ID - private UUID _AssetID; - /// The assets unique ID - public UUID AssetID - { - get { return _AssetID; } - internal set { _AssetID = value; } - } - - /// - /// The "type" of asset, Notecard, Animation, etc - /// - public abstract AssetType AssetType - { - get; - } - - /// - /// Construct a new Asset object - /// - public Asset() { } - - /// - /// Construct a new Asset object - /// - /// A unique specific to this asset - /// A byte array containing the raw asset data - public Asset(UUID assetID, byte[] assetData) - { - _AssetID = assetID; - AssetData = assetData; - } - - /// - /// Regenerates the AssetData byte array from the properties - /// of the derived class. - /// - public abstract void Encode(); - - /// - /// Decodes the AssetData, placing it in appropriate properties of the derived - /// class. - /// - /// True if the asset decoding succeeded, otherwise false - public abstract bool Decode(); - } - - /// - /// Represents an Animation - /// - public class AssetAnimation : Asset - { - /// Override the base classes AssetType - public override AssetType AssetType { get { return AssetType.Animation; } } - - /// Default Constructor - public AssetAnimation() { } - - /// - /// Construct an Asset object of type Animation - /// - /// A unique specific to this asset - /// A byte array containing the raw asset data - public AssetAnimation(UUID assetID, byte[] assetData) - : base(assetID, assetData) - { - AssetData = assetData; - } - - public override void Encode() { } - public override bool Decode() { return true; } - } - - /// - /// Represents a string of characters encoded with specific formatting properties - /// - public class AssetNotecard : Asset - { - /// Override the base classes AssetType - public override AssetType AssetType { get { return AssetType.Notecard; } } - - /// A text string containing the raw contents of the notecard - public string Text = null; - - /// Construct an Asset of type Notecard - public AssetNotecard() { } - - /// - /// Construct an Asset object of type Notecard - /// - /// A unique specific to this asset - /// A byte array containing the raw asset data - public AssetNotecard(UUID assetID, byte[] assetData) : base(assetID, assetData) - { - Decode(); - } - - /// - /// Construct an Asset object of type Notecard - /// - /// A text string containing the raw contents of the notecard - public AssetNotecard(string text) - { - Text = text; - Encode(); - } - - /// - /// Encode the raw contents of a string with the specific Linden Text properties - /// - public override void Encode() - { - string temp = "Linden text version 2\n{\nLLEmbeddedItems version 1\n{\ncount 0\n}\nText length "; - temp += Text.Length + "\n"; - temp += Text; - temp += "}"; - AssetData = Utils.StringToBytes(temp); - } - - /// - /// Decode the raw asset data including the Linden Text properties - /// - /// true if the AssetData was successfully decoded to a string - public override bool Decode() - { - Text = Utils.BytesToString(AssetData); - return true; - } - } - - /// - /// Represents a Landmark with RegionID and Position vector - /// - public class AssetLandmark : Asset - { - /// Override the base classes AssetType - public override AssetType AssetType { get { return AssetType.Landmark; } } - - /// UUID of the Landmark target region - public UUID RegionID = UUID.Zero; - /// Local position of the target - public Vector3 Position = Vector3.Zero; - - /// Construct an Asset of type Landmark - public AssetLandmark() { } - - /// - /// Construct an Asset object of type Landmark - /// - /// A unique specific to this asset - /// A byte array containing the raw asset data - public AssetLandmark(UUID assetID, byte[] assetData) - : base(assetID, assetData) - { - Decode(); - } - - /// - /// Constuct an asset of type Landmark - /// - /// UUID of the target region - /// Local position of landmark - public AssetLandmark(UUID regionID, Vector3 pos) - { - RegionID = regionID; - Position = pos; - Encode(); - } - - /// - /// Encode the raw contents of a string with the specific Landmark format - /// - public override void Encode() - { - string temp = "Landmark version 2\n"; - temp += "region_id " + RegionID + "\n"; - temp += String.Format("local_pos {0:0.00} {1:0.00} {2:0.00}\n", Position.X, Position.Y, Position.Z); - AssetData = Utils.StringToBytes(temp); - } - - /// - /// Decode the raw asset data, populating the RegionID and Position - /// - /// true if the AssetData was successfully decoded to a UUID and Vector - public override bool Decode() - { - String text = Utils.BytesToString(AssetData); - if(text.ToLower().Contains("landmark version 2")) - { - RegionID = new UUID(text.Substring(text.IndexOf("region_id") + 10, 36)); - String vecDelim = " "; - String[] vecStrings = text.Substring(text.IndexOf("local_pos") + 10).Split(vecDelim.ToCharArray()); - if(vecStrings.Length == 3) - { - Position = new Vector3(float.Parse(vecStrings[0]), float.Parse(vecStrings[1]), float.Parse(vecStrings[2])); - return true; - } - } - return false; - } - } - - /// - /// Represents an LSL Text object containing a string of UTF encoded characters - /// - public class AssetScriptText : Asset - { - /// Override the base classes AssetType - public override AssetType AssetType { get { return AssetType.LSLText; } } - - /// A string of characters represting the script contents - public string Source; - - /// Initializes a new AssetScriptText object - public AssetScriptText() { } - - /// - /// Initializes a new AssetScriptText object with parameters - /// - /// A unique specific to this asset - /// A byte array containing the raw asset data - public AssetScriptText(UUID assetID, byte[] assetData) : base(assetID, assetData) { } - - /// - /// Initializes a new AssetScriptText object with parameters - /// - /// A string containing the scripts contents - public AssetScriptText(string source) - { - Source = source; - } - - /// - /// Encode a string containing the scripts contents into byte encoded AssetData - /// - public override void Encode() - { - AssetData = Utils.StringToBytes(Source); - } - - /// - /// Decode a byte array containing the scripts contents into a string - /// - /// true if decoding is successful - public override bool Decode() - { - Source = Utils.BytesToString(AssetData); - return true; - } - } - - /// - /// Represents an AssetScriptBinary object containing the - /// LSO compiled bytecode of an LSL script - /// - public class AssetScriptBinary : Asset - { - /// Override the base classes AssetType - public override AssetType AssetType { get { return AssetType.LSLBytecode; } } - - /// Initializes a new instance of an AssetScriptBinary object - public AssetScriptBinary() { } - - /// Initializes a new instance of an AssetScriptBinary object with parameters - /// A unique specific to this asset - /// A byte array containing the raw asset data - public AssetScriptBinary(UUID assetID, byte[] assetData) - : base(assetID, assetData) - { - AssetData = assetData; - } - - /// - /// TODO: Encodes a scripts contents into a LSO Bytecode file - /// - public override void Encode() { } - - /// - /// TODO: Decode LSO Bytecode into a string - /// - /// true - public override bool Decode() { return true; } - } - - /// - /// Represents a Sound Asset - /// - public class AssetSound : Asset - { - /// Override the base classes AssetType - public override AssetType AssetType { get { return AssetType.Sound; } } - - /// Initializes a new instance of an AssetSound object - public AssetSound() { } - - /// Initializes a new instance of an AssetSound object with parameters - /// A unique specific to this asset - /// A byte array containing the raw asset data - public AssetSound(UUID assetID, byte[] assetData) - : base(assetID, assetData) - { - AssetData = assetData; - } - - /// - /// TODO: Encodes a sound file - /// - public override void Encode() { } - - /// - /// TODO: Decode a sound file - /// - /// true - public override bool Decode() { return true; } - } - - /// - /// Represents a texture - /// - public class AssetTexture : Asset - { - /// Override the base classes AssetType - public override AssetType AssetType { get { return AssetType.Texture; } } - - /// A object containing image data - public ManagedImage Image; - - /// - public OpenJPEG.J2KLayerInfo[] LayerInfo; - - /// - public int Components; - - /// Initializes a new instance of an AssetTexture object - public AssetTexture() { } - - /// - /// Initializes a new instance of an AssetTexture object - /// - /// A unique specific to this asset - /// A byte array containing the raw asset data - public AssetTexture(UUID assetID, byte[] assetData) : base(assetID, assetData) { } - - /// - /// Initializes a new instance of an AssetTexture object - /// - /// A object containing texture data - public AssetTexture(ManagedImage image) - { - Image = image; - Components = 0; - if ((Image.Channels & ManagedImage.ImageChannels.Color) != 0) - Components += 3; - if ((Image.Channels & ManagedImage.ImageChannels.Gray) != 0) - ++Components; - if ((Image.Channels & ManagedImage.ImageChannels.Bump) != 0) - ++Components; - if ((Image.Channels & ManagedImage.ImageChannels.Alpha) != 0) - ++Components; - } - - /// - /// Populates the byte array with a JPEG2000 - /// encoded image created from the data in - /// - public override void Encode() - { - AssetData = OpenJPEG.Encode(Image); - } - - /// - /// Decodes the JPEG2000 data in AssetData to the - /// object - /// - /// True if the decoding was successful, otherwise false - public override bool Decode() - { - Components = 0; - - if (OpenJPEG.DecodeToImage(AssetData, out Image)) - { - if ((Image.Channels & ManagedImage.ImageChannels.Color) != 0) - Components += 3; - if ((Image.Channels & ManagedImage.ImageChannels.Gray) != 0) - ++Components; - if ((Image.Channels & ManagedImage.ImageChannels.Bump) != 0) - ++Components; - if ((Image.Channels & ManagedImage.ImageChannels.Alpha) != 0) - ++Components; - - return true; - } - else - { - return false; - } - } - - /// - /// Decodes the begin and end byte positions for each quality layer in - /// the image - /// - /// - public bool DecodeLayerBoundaries() - { - return OpenJPEG.DecodeLayerBoundaries(AssetData, out LayerInfo, out Components); - } - } - - /// - /// Represents a primitive asset - /// - public class AssetPrim : Asset - { - - /// Override the base classes AssetType - public override AssetType AssetType { get { return AssetType.Object; } } - - /// Initializes a new instance of an AssetPrim object - public AssetPrim() { } - - - /// - /// TODO: - /// - public override void Encode() { } - - /// - /// TODO: - /// - /// true - public override bool Decode() { return true; } - } - - /// - /// Represents a Wearable Asset, Clothing, Hair, Skin, Etc - /// - public abstract class AssetWearable : Asset - { - /// A string containing the name of the asset - public string Name = String.Empty; - /// A string containing a short description of the asset - public string Description = String.Empty; - /// The Assets WearableType - public WearableType WearableType = WearableType.Shape; - /// The For-Sale status of the object - public SaleType ForSale; - /// An Integer representing the purchase price of the asset - public int SalePrice; - /// The of the assets creator - public UUID Creator; - /// The of the assets current owner - public UUID Owner; - /// The of the assets prior owner - public UUID LastOwner; - /// The of the Group this asset is set to - public UUID Group; - /// True if the asset is owned by a - public bool GroupOwned; - /// The Permissions mask of the asset - public Permissions Permissions; - /// A Dictionary containing Key/Value pairs of the objects parameters - public Dictionary Params = new Dictionary(); - /// A Dictionary containing Key/Value pairs where the Key is the textures Index and the Value is the Textures - public Dictionary Textures = new Dictionary(); - - /// Initializes a new instance of an AssetWearable object - public AssetWearable() { } - - /// Initializes a new instance of an AssetWearable object with parameters - /// A unique specific to this asset - /// A byte array containing the raw asset data - public AssetWearable(UUID assetID, byte[] assetData) : base(assetID, assetData) { } - - /// Initializes a new instance of an AssetWearable object with parameters - /// A string containing the asset parameters - public AssetWearable(string source) - { - AssetData = Utils.StringToBytes(source); - } - - /// - /// Decode an assets byte encoded data to a string - /// - /// true if the asset data was decoded successfully - public override bool Decode() - { - int version = -1; - Permissions = new Permissions(); - string data = Utils.BytesToString(AssetData); - - data = data.Replace("\r", String.Empty); - string[] lines = data.Split('\n'); - for (int stri = 0; stri < lines.Length; stri++) - { - if (stri == 0) - { - string versionstring = lines[stri]; - version = Int32.Parse(versionstring.Split(' ')[2]); - if (version != 22 && version != 18) - return false; - } - else if (stri == 1) - { - Name = lines[stri]; - } - else if (stri == 2) - { - Description = lines[stri]; - } - else - { - string line = lines[stri].Trim(); - string[] fields = line.Split('\t'); - - if (fields.Length == 1) - { - fields = line.Split(' '); - if (fields[0] == "parameters") - { - int count = Int32.Parse(fields[1]) + stri; - for (; stri < count; ) - { - stri++; - line = lines[stri].Trim(); - fields = line.Split(' '); - - int id = Int32.Parse(fields[0]); - if (fields[1] == ",") - fields[1] = "0"; - else - fields[1] = fields[1].Replace(',', '.'); - - float weight = float.Parse(fields[1], System.Globalization.NumberStyles.Float, - Utils.EnUsCulture.NumberFormat); - - Params[id] = weight; - } - } - else if (fields[0] == "textures") - { - int count = Int32.Parse(fields[1]) + stri; - for (; stri < count; ) - { - stri++; - line = lines[stri].Trim(); - fields = line.Split(' '); - - AppearanceManager.TextureIndex id = (AppearanceManager.TextureIndex)Int32.Parse(fields[0]); - UUID texture = new UUID(fields[1]); - - Textures[id] = texture; - } - } - else if (fields[0] == "type") - { - WearableType = (WearableType)Int32.Parse(fields[1]); - } - - } - else if (fields.Length == 2) - { - switch (fields[0]) - { - case "creator_mask": - // Deprecated, apply this as the base mask - Permissions.BaseMask = (PermissionMask)UInt32.Parse(fields[1], System.Globalization.NumberStyles.HexNumber); - break; - case "base_mask": - Permissions.BaseMask = (PermissionMask)UInt32.Parse(fields[1], System.Globalization.NumberStyles.HexNumber); - break; - case "owner_mask": - Permissions.OwnerMask = (PermissionMask)UInt32.Parse(fields[1], System.Globalization.NumberStyles.HexNumber); - break; - case "group_mask": - Permissions.GroupMask = (PermissionMask)UInt32.Parse(fields[1], System.Globalization.NumberStyles.HexNumber); - break; - case "everyone_mask": - Permissions.EveryoneMask = (PermissionMask)UInt32.Parse(fields[1], System.Globalization.NumberStyles.HexNumber); - break; - case "next_owner_mask": - Permissions.NextOwnerMask = (PermissionMask)UInt32.Parse(fields[1], System.Globalization.NumberStyles.HexNumber); - break; - case "creator_id": - Creator = new UUID(fields[1]); - break; - case "owner_id": - Owner = new UUID(fields[1]); - break; - case "last_owner_id": - LastOwner = new UUID(fields[1]); - break; - case "group_id": - Group = new UUID(fields[1]); - break; - case "group_owned": - GroupOwned = (Int32.Parse(fields[1]) != 0); - break; - case "sale_type": - ForSale = Utils.StringToSaleType(fields[1]); - break; - case "sale_price": - SalePrice = Int32.Parse(fields[1]); - break; - case "sale_info": - // Container for sale_type and sale_price, ignore - break; - default: - return false; - } - } - } - } - - return true; - } - - /// - /// Encode the assets string represantion into a format consumable by the asset server - /// - public override void Encode() - { - const string NL = "\n"; - - StringBuilder data = new StringBuilder("LLWearable version 22\n"); - data.Append(Name); data.Append(NL); data.Append(NL); - data.Append("\tpermissions 0\n\t{\n"); - data.Append("\t\tbase_mask\t"); data.Append(Utils.UIntToHexString((uint)Permissions.BaseMask)); data.Append(NL); - data.Append("\t\towner_mask\t"); data.Append(Utils.UIntToHexString((uint)Permissions.OwnerMask)); data.Append(NL); - data.Append("\t\tgroup_mask\t"); data.Append(Utils.UIntToHexString((uint)Permissions.GroupMask)); data.Append(NL); - data.Append("\t\teveryone_mask\t"); data.Append(Utils.UIntToHexString((uint)Permissions.EveryoneMask)); data.Append(NL); - data.Append("\t\tnext_owner_mask\t"); data.Append(Utils.UIntToHexString((uint)Permissions.NextOwnerMask)); data.Append(NL); - data.Append("\t\tcreator_id\t"); data.Append(Creator.ToString()); data.Append(NL); - data.Append("\t\towner_id\t"); data.Append(Owner.ToString()); data.Append(NL); - data.Append("\t\tlast_owner_id\t"); data.Append(LastOwner.ToString()); data.Append(NL); - data.Append("\t\tgroup_id\t"); data.Append(Group.ToString()); data.Append(NL); - if (GroupOwned) data.Append("\t\tgroup_owned\t1\n"); - data.Append("\t}\n"); - data.Append("\tsale_info\t0\n"); - data.Append("\t{\n"); - data.Append("\t\tsale_type\t"); data.Append(Utils.SaleTypeToString(ForSale)); data.Append(NL); - data.Append("\t\tsale_price\t"); data.Append(SalePrice); data.Append(NL); - data.Append("\t}\n"); - data.Append("type "); data.Append((int)WearableType); data.Append(NL); - - data.Append("parameters "); data.Append(Params.Count); data.Append(NL); - foreach (KeyValuePair param in Params) - { - data.Append(param.Key); data.Append(" "); data.Append(Helpers.FloatToTerseString(param.Value)); data.Append(NL); - } - - data.Append("textures "); data.Append(Textures.Count); data.Append(NL); - foreach (KeyValuePair texture in Textures) - { - data.Append((byte)texture.Key); data.Append(" "); data.Append(texture.Value.ToString()); data.Append(NL); - } - - AssetData = Utils.StringToBytes(data.ToString()); - } - } - - - /// - /// Represents an that can be worn on an avatar - /// such as a Shirt, Pants, etc. - /// - public class AssetClothing : AssetWearable - { - /// Override the base classes AssetType - public override AssetType AssetType { get { return AssetType.Clothing; } } - - /// Initializes a new instance of an AssetScriptBinary object - public AssetClothing() { } - - /// Initializes a new instance of an AssetScriptBinary object with parameters - /// A unique specific to this asset - /// A byte array containing the raw asset data - public AssetClothing(UUID assetID, byte[] assetData) : base(assetID, assetData) { } - - /// Initializes a new instance of an AssetScriptBinary object with parameters - /// A string containing the Clothings data - public AssetClothing(string source) : base(source) { } - } - - /// - /// Represents an that represents an avatars body ie: Hair, Etc. - /// - public class AssetBodypart : AssetWearable - { - /// Override the base classes AssetType - public override AssetType AssetType { get { return AssetType.Bodypart; } } - - /// Initializes a new instance of an AssetBodyPart object - public AssetBodypart() { } - - /// Initializes a new instance of an AssetBodyPart object with parameters - /// A unique specific to this asset - /// A byte array containing the raw asset data - public AssetBodypart(UUID assetID, byte[] assetData) : base(assetID, assetData) { } - - - /// Initializes a new instance of an AssetBodyPart object with parameters - /// A string representing the values of the Bodypart - public AssetBodypart(string source) : base(source) { } - } -} diff --git a/OpenMetaverse/Assets/Archiving/ArchiveConstants.cs b/OpenMetaverse/Assets/Archiving/ArchiveConstants.cs new file mode 100644 index 00000000..b3ce3da8 --- /dev/null +++ b/OpenMetaverse/Assets/Archiving/ArchiveConstants.cs @@ -0,0 +1,122 @@ +/* + * Copyright (c) 2009, openmetaverse.org + * All rights reserved. + * + * - 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. + * - Neither the name of the openmetaverse.org 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 COPYRIGHT HOLDERS AND CONTRIBUTORS "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 COPYRIGHT OWNER OR 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 System.Collections.Generic; +using OpenMetaverse; + +namespace OpenMetaverse.Assets +{ + /// + /// Constants for the archiving module + /// + public class ArchiveConstants + { + /// + /// The location of the archive control file + /// + public static readonly string CONTROL_FILE_PATH = "archive.xml"; + + /// + /// Path for the assets held in an archive + /// + public static readonly string ASSETS_PATH = "assets/"; + + /// + /// Path for the prims file + /// + public static readonly string OBJECTS_PATH = "objects/"; + + /// + /// Path for terrains. Technically these may be assets, but I think it's quite nice to split them out. + /// + public static readonly string TERRAINS_PATH = "terrains/"; + + /// + /// Path for region settings. + /// + public static readonly string SETTINGS_PATH = "settings/"; + + /// + /// The character the separates the uuid from extension information in an archived asset filename + /// + public static readonly string ASSET_EXTENSION_SEPARATOR = "_"; + + /// + /// Extensions used for asset types in the archive + /// + public static readonly IDictionary ASSET_TYPE_TO_EXTENSION = new Dictionary(); + public static readonly IDictionary EXTENSION_TO_ASSET_TYPE = new Dictionary(); + + static ArchiveConstants() + { + ASSET_TYPE_TO_EXTENSION[AssetType.Animation] = ASSET_EXTENSION_SEPARATOR + "animation.bvh"; + ASSET_TYPE_TO_EXTENSION[AssetType.Bodypart] = ASSET_EXTENSION_SEPARATOR + "bodypart.txt"; + ASSET_TYPE_TO_EXTENSION[AssetType.CallingCard] = ASSET_EXTENSION_SEPARATOR + "callingcard.txt"; + ASSET_TYPE_TO_EXTENSION[AssetType.Clothing] = ASSET_EXTENSION_SEPARATOR + "clothing.txt"; + ASSET_TYPE_TO_EXTENSION[AssetType.Folder] = ASSET_EXTENSION_SEPARATOR + "folder.txt"; // Not sure if we'll ever see this + ASSET_TYPE_TO_EXTENSION[AssetType.Gesture] = ASSET_EXTENSION_SEPARATOR + "gesture.txt"; + ASSET_TYPE_TO_EXTENSION[AssetType.ImageJPEG] = ASSET_EXTENSION_SEPARATOR + "image.jpg"; + ASSET_TYPE_TO_EXTENSION[AssetType.ImageTGA] = ASSET_EXTENSION_SEPARATOR + "image.tga"; + ASSET_TYPE_TO_EXTENSION[AssetType.Landmark] = ASSET_EXTENSION_SEPARATOR + "landmark.txt"; + ASSET_TYPE_TO_EXTENSION[AssetType.LostAndFoundFolder] = ASSET_EXTENSION_SEPARATOR + "lostandfoundfolder.txt"; // Not sure if we'll ever see this + ASSET_TYPE_TO_EXTENSION[AssetType.LSLBytecode] = ASSET_EXTENSION_SEPARATOR + "bytecode.lso"; + ASSET_TYPE_TO_EXTENSION[AssetType.LSLText] = ASSET_EXTENSION_SEPARATOR + "script.lsl"; + ASSET_TYPE_TO_EXTENSION[AssetType.Notecard] = ASSET_EXTENSION_SEPARATOR + "notecard.txt"; + ASSET_TYPE_TO_EXTENSION[AssetType.Object] = ASSET_EXTENSION_SEPARATOR + "object.xml"; + ASSET_TYPE_TO_EXTENSION[AssetType.RootFolder] = ASSET_EXTENSION_SEPARATOR + "rootfolder.txt"; // Not sure if we'll ever see this + ASSET_TYPE_TO_EXTENSION[AssetType.Simstate] = ASSET_EXTENSION_SEPARATOR + "simstate.bin"; // Not sure if we'll ever see this + ASSET_TYPE_TO_EXTENSION[AssetType.SnapshotFolder] = ASSET_EXTENSION_SEPARATOR + "snapshotfolder.txt"; // Not sure if we'll ever see this + ASSET_TYPE_TO_EXTENSION[AssetType.Sound] = ASSET_EXTENSION_SEPARATOR + "sound.ogg"; + ASSET_TYPE_TO_EXTENSION[AssetType.SoundWAV] = ASSET_EXTENSION_SEPARATOR + "sound.wav"; + ASSET_TYPE_TO_EXTENSION[AssetType.Texture] = ASSET_EXTENSION_SEPARATOR + "texture.jp2"; + ASSET_TYPE_TO_EXTENSION[AssetType.TextureTGA] = ASSET_EXTENSION_SEPARATOR + "texture.tga"; + ASSET_TYPE_TO_EXTENSION[AssetType.TrashFolder] = ASSET_EXTENSION_SEPARATOR + "trashfolder.txt"; // Not sure if we'll ever see this + + EXTENSION_TO_ASSET_TYPE[ASSET_EXTENSION_SEPARATOR + "animation.bvh"] = AssetType.Animation; + EXTENSION_TO_ASSET_TYPE[ASSET_EXTENSION_SEPARATOR + "bodypart.txt"] = AssetType.Bodypart; + EXTENSION_TO_ASSET_TYPE[ASSET_EXTENSION_SEPARATOR + "callingcard.txt"] = AssetType.CallingCard; + EXTENSION_TO_ASSET_TYPE[ASSET_EXTENSION_SEPARATOR + "clothing.txt"] = AssetType.Clothing; + EXTENSION_TO_ASSET_TYPE[ASSET_EXTENSION_SEPARATOR + "folder.txt"] = AssetType.Folder; + EXTENSION_TO_ASSET_TYPE[ASSET_EXTENSION_SEPARATOR + "gesture.txt"] = AssetType.Gesture; + EXTENSION_TO_ASSET_TYPE[ASSET_EXTENSION_SEPARATOR + "image.jpg"] = AssetType.ImageJPEG; + EXTENSION_TO_ASSET_TYPE[ASSET_EXTENSION_SEPARATOR + "image.tga"] = AssetType.ImageTGA; + EXTENSION_TO_ASSET_TYPE[ASSET_EXTENSION_SEPARATOR + "landmark.txt"] = AssetType.Landmark; + EXTENSION_TO_ASSET_TYPE[ASSET_EXTENSION_SEPARATOR + "lostandfoundfolder.txt"] = AssetType.LostAndFoundFolder; + EXTENSION_TO_ASSET_TYPE[ASSET_EXTENSION_SEPARATOR + "bytecode.lso"] = AssetType.LSLBytecode; + EXTENSION_TO_ASSET_TYPE[ASSET_EXTENSION_SEPARATOR + "script.lsl"] = AssetType.LSLText; + EXTENSION_TO_ASSET_TYPE[ASSET_EXTENSION_SEPARATOR + "notecard.txt"] = AssetType.Notecard; + EXTENSION_TO_ASSET_TYPE[ASSET_EXTENSION_SEPARATOR + "object.xml"] = AssetType.Object; + EXTENSION_TO_ASSET_TYPE[ASSET_EXTENSION_SEPARATOR + "rootfolder.txt"] = AssetType.RootFolder; + EXTENSION_TO_ASSET_TYPE[ASSET_EXTENSION_SEPARATOR + "simstate.bin"] = AssetType.Simstate; + EXTENSION_TO_ASSET_TYPE[ASSET_EXTENSION_SEPARATOR + "snapshotfolder.txt"] = AssetType.SnapshotFolder; + EXTENSION_TO_ASSET_TYPE[ASSET_EXTENSION_SEPARATOR + "sound.ogg"] = AssetType.Sound; + EXTENSION_TO_ASSET_TYPE[ASSET_EXTENSION_SEPARATOR + "sound.wav"] = AssetType.SoundWAV; + EXTENSION_TO_ASSET_TYPE[ASSET_EXTENSION_SEPARATOR + "texture.jp2"] = AssetType.Texture; + EXTENSION_TO_ASSET_TYPE[ASSET_EXTENSION_SEPARATOR + "texture.tga"] = AssetType.TextureTGA; + EXTENSION_TO_ASSET_TYPE[ASSET_EXTENSION_SEPARATOR + "trashfolder.txt"] = AssetType.TrashFolder; + } + } +} diff --git a/OpenMetaverse/Assets/Archiving/AssetsArchiver.cs b/OpenMetaverse/Assets/Archiving/AssetsArchiver.cs new file mode 100644 index 00000000..d94af687 --- /dev/null +++ b/OpenMetaverse/Assets/Archiving/AssetsArchiver.cs @@ -0,0 +1,150 @@ +/* + * Copyright (c) 2009, openmetaverse.org + * All rights reserved. + * + * - 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. + * - Neither the name of the openmetaverse.org 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 COPYRIGHT HOLDERS AND CONTRIBUTORS "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 COPYRIGHT OWNER OR 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 System; +using System.Collections.Generic; +using System.IO; +using System.Reflection; +using System.Xml; +using OpenMetaverse; + +namespace OpenMetaverse.Assets +{ + /// + /// Archives assets + /// + public class AssetsArchiver + { + /// + /// Post a message to the log every x assets as a progress bar + /// + //static int LOG_ASSET_LOAD_NOTIFICATION_INTERVAL = 50; + + /// + /// Archive assets + /// + protected IDictionary m_assets; + + public AssetsArchiver(IDictionary assets) + { + m_assets = assets; + } + + /// + /// Archive the assets given to this archiver to the given archive. + /// + /// + public void Archive(TarArchiveWriter archive) + { + //WriteMetadata(archive); + WriteData(archive); + } + + /// + /// Write an assets metadata file to the given archive + /// + /// + protected void WriteMetadata(TarArchiveWriter archive) + { + StringWriter sw = new StringWriter(); + XmlTextWriter xtw = new XmlTextWriter(sw); + + xtw.Formatting = Formatting.Indented; + xtw.WriteStartDocument(); + + xtw.WriteStartElement("assets"); + + foreach (UUID uuid in m_assets.Keys) + { + Asset asset = m_assets[uuid]; + + if (asset != null) + { + xtw.WriteStartElement("asset"); + + string extension = string.Empty; + + if (ArchiveConstants.ASSET_TYPE_TO_EXTENSION.ContainsKey(asset.AssetType)) + { + extension = ArchiveConstants.ASSET_TYPE_TO_EXTENSION[asset.AssetType]; + } + + xtw.WriteElementString("filename", uuid.ToString() + extension); + + xtw.WriteElementString("name", uuid.ToString()); + xtw.WriteElementString("description", String.Empty); + xtw.WriteElementString("asset-type", asset.AssetType.ToString()); + + xtw.WriteEndElement(); + } + } + + xtw.WriteEndElement(); + + xtw.WriteEndDocument(); + + archive.WriteFile("assets.xml", sw.ToString()); + } + + /// + /// Write asset data files to the given archive + /// + /// + protected void WriteData(TarArchiveWriter archive) + { + // It appears that gtar, at least, doesn't need the intermediate directory entries in the tar + //archive.AddDir("assets"); + + int assetsAdded = 0; + + foreach (UUID uuid in m_assets.Keys) + { + Asset asset = m_assets[uuid]; + + string extension = string.Empty; + + if (ArchiveConstants.ASSET_TYPE_TO_EXTENSION.ContainsKey(asset.AssetType)) + { + extension = ArchiveConstants.ASSET_TYPE_TO_EXTENSION[asset.AssetType]; + } + else + { + Logger.Log(String.Format( + "Unrecognized asset type {0} with uuid {1}. This asset will be saved but not reloaded", + asset.AssetType, asset.AssetID), Helpers.LogLevel.Warning); + } + + asset.Encode(); + + archive.WriteFile( + ArchiveConstants.ASSETS_PATH + uuid.ToString() + extension, + asset.AssetData); + + assetsAdded++; + } + } + } +} diff --git a/OpenMetaverse/Assets/Archiving/OarFile.cs b/OpenMetaverse/Assets/Archiving/OarFile.cs new file mode 100644 index 00000000..13e974c2 --- /dev/null +++ b/OpenMetaverse/Assets/Archiving/OarFile.cs @@ -0,0 +1,581 @@ +/* + * Copyright (c) 2009, openmetaverse.org + * All rights reserved. + * + * - 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. + * - Neither the name of the openmetaverse.org 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 COPYRIGHT HOLDERS AND CONTRIBUTORS "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 COPYRIGHT OWNER OR 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 System; +using System.Collections.Generic; +using System.IO; +using System.IO.Compression; +using System.Text; +using System.Xml; +using OpenMetaverse; + +namespace OpenMetaverse.Assets +{ + public static class OarFile + { + public delegate void AssetLoadedCallback(Asset asset); + public delegate void TerrainLoadedCallback(float[,] terrain); + + #region Archive Loading + + public static void UnpackageArchive(string filename, AssetLoadedCallback assetCallback, TerrainLoadedCallback terrainCallback) + { + int successfulAssetRestores = 0; + int failedAssetRestores = 0; + List serialisedSceneObjects = new List(); + + try + { + using (Stream loadStream = new GZipStream(new FileStream(filename, FileMode.Open, FileAccess.Read), CompressionMode.Decompress)) + { + TarArchiveReader archive = new TarArchiveReader(loadStream); + + string filePath = "ERROR"; + + byte[] data; + TarArchiveReader.TarEntryType entryType; + + while ((data = archive.ReadEntry(out filePath, out entryType)) != null) + { + if (filePath.StartsWith(ArchiveConstants.OBJECTS_PATH)) + { + serialisedSceneObjects.Add(data); + } + else if (filePath.StartsWith(ArchiveConstants.ASSETS_PATH)) + { + if (LoadAsset(filePath, data, assetCallback)) + successfulAssetRestores++; + else + failedAssetRestores++; + } + else if (filePath.StartsWith(ArchiveConstants.TERRAINS_PATH)) + { + LoadTerrain(filePath, data, terrainCallback); + } + else if (filePath.StartsWith(ArchiveConstants.SETTINGS_PATH)) + { + // FIXME: Support this + //LoadRegionSettings(filePath, data); + } + } + + archive.Close(); + } + } + catch (Exception e) + { + Logger.Log("[OarFile] Error loading OAR file: " + e.Message, Helpers.LogLevel.Error); + return; + } + + if (failedAssetRestores > 0) + Logger.Log(String.Format("[OarFile]: Failed to load {0} assets", failedAssetRestores), Helpers.LogLevel.Warning); + + for (int i = 0; i < serialisedSceneObjects.Count; i++) + { + byte[] objectData = serialisedSceneObjects[i]; + + // Deserialize the XML bytes + LoadObjects(objectData, assetCallback); + } + } + + private static bool LoadAsset(string assetPath, byte[] data, AssetLoadedCallback assetCallback) + { + // Right now we're nastily obtaining the UUID from the filename + string filename = assetPath.Remove(0, ArchiveConstants.ASSETS_PATH.Length); + int i = filename.LastIndexOf(ArchiveConstants.ASSET_EXTENSION_SEPARATOR); + + if (i == -1) + { + Logger.Log(String.Format( + "[OarFile]: Could not find extension information in asset path {0} since it's missing the separator {1}. Skipping", + assetPath, ArchiveConstants.ASSET_EXTENSION_SEPARATOR), Helpers.LogLevel.Warning); + return false; + } + + string extension = filename.Substring(i); + UUID uuid; + UUID.TryParse(filename.Remove(filename.Length - extension.Length), out uuid); + + if (ArchiveConstants.EXTENSION_TO_ASSET_TYPE.ContainsKey(extension)) + { + AssetType assetType = ArchiveConstants.EXTENSION_TO_ASSET_TYPE[extension]; + Asset asset = null; + + switch (assetType) + { + case AssetType.Animation: + asset = new AssetAnimation(uuid, data); + break; + case AssetType.Bodypart: + asset = new AssetBodypart(uuid, data); + break; + case AssetType.Clothing: + asset = new AssetClothing(uuid, data); + break; + case AssetType.LSLBytecode: + asset = new AssetScriptBinary(uuid, data); + break; + case AssetType.LSLText: + asset = new AssetScriptText(uuid, data); + break; + case AssetType.Notecard: + asset = new AssetNotecard(uuid, data); + break; + case AssetType.Sound: + asset = new AssetSound(uuid, data); + break; + case AssetType.Texture: + asset = new AssetTexture(uuid, data); + break; + default: + Logger.Log("[OarFile] Unhandled asset type " + assetType, Helpers.LogLevel.Error); + break; + } + + if (asset != null) + { + asset.Decode(); + assetCallback(asset); + return true; + } + } + + Logger.Log("[OarFile] Failed to load asset", Helpers.LogLevel.Warning); + return false; + } + + private static bool LoadTerrain(string filePath, byte[] data, TerrainLoadedCallback terrainCallback) + { + float[,] terrain = new float[256, 256]; + bool loaded = false; + + switch (Path.GetExtension(filePath)) + { + case ".r32": + case ".f32": + // RAW32 + if (data.Length == 256 * 256 * 4) + { + int pos = 0; + for (int y = 0; y < 256; y++) + { + for (int x = 0; x < 256; x++) + { + terrain[y, x] = Utils.Clamp(Utils.BytesToFloat(data, pos), 0.0f, 255.0f); + pos += 4; + } + } + + loaded = true; + } + else + { + Logger.Log("[OarFile] RAW32 terrain file " + filePath + " has the wrong number of bytes: " + data.Length, + Helpers.LogLevel.Warning); + } + break; + case ".ter": + // Terragen + case ".raw": + // LLRAW + case ".jpg": + case ".jpeg": + // JPG + case ".bmp": + // BMP + case ".png": + // PNG + case ".gif": + // GIF + case ".tif": + case ".tiff": + // TIFF + default: + Logger.Log("[OarFile] Unrecognized terrain format in " + filePath, Helpers.LogLevel.Warning); + break; + } + + if (loaded) + terrainCallback(terrain); + + return loaded; + } + + private static void LoadObjects(byte[] objectData, AssetLoadedCallback assetCallback) + { + // TODO: If we can get by without XmlDocument it will fix the memory problems when loading large XML files + XmlDocument doc = new XmlDocument(); + + using (XmlTextReader reader = new XmlTextReader(new MemoryStream(objectData))) + { + reader.WhitespaceHandling = WhitespaceHandling.None; + doc.Load(reader); + } + + XmlNode rootNode = doc.FirstChild; + + if (rootNode.LocalName.Equals("scene")) + { + foreach (XmlNode node in rootNode.ChildNodes) + { + AssetPrim linkset = new AssetPrim(node.OuterXml); + if (linkset != null) + assetCallback(linkset); + } + } + else + { + AssetPrim linkset = new AssetPrim(rootNode.OuterXml); + if (linkset != null) + assetCallback(linkset); + } + } + + #endregion Archive Loading + + #region Archive Saving + + public static void PackageArchive(string directoryName, string filename) + { + const string ARCHIVE_XML = "\n"; + + TarArchiveWriter archive = new TarArchiveWriter(new GZipStream(new FileStream(filename, FileMode.Create), CompressionMode.Compress)); + + // Create the archive.xml file + archive.WriteFile("archive.xml", ARCHIVE_XML); + + // Add the assets + string[] files = Directory.GetFiles(directoryName + "/assets"); + foreach (string file in files) + archive.WriteFile("assets/" + Path.GetFileName(file), File.ReadAllBytes(file)); + + // Add the objects + files = Directory.GetFiles(directoryName + "/objects"); + foreach (string file in files) + archive.WriteFile("objects/" + Path.GetFileName(file), File.ReadAllBytes(file)); + + // Add the terrain(s) + files = Directory.GetFiles(directoryName + "/terrains"); + foreach (string file in files) + archive.WriteFile("terrains/" + Path.GetFileName(file), File.ReadAllBytes(file)); + + archive.Close(); + } + + public static void SavePrims(IList prims, string primsPath, string assetsPath, string textureCacheFolder) + { + Dictionary textureList = new Dictionary(); + + // Delete all of the old linkset files + try { Directory.Delete(primsPath, true); } + catch (Exception) { } + + // Create a new folder for the linkset files + try { Directory.CreateDirectory(primsPath); } + catch (Exception ex) + { + Logger.Log("Failed saving prims: " + ex.Message, Helpers.LogLevel.Error); + return; + } + + foreach (AssetPrim assetPrim in prims) + { + SavePrim(assetPrim, Path.Combine(primsPath, "Primitive_" + assetPrim.Parent.ID + ".xml")); + + CollectTextures(assetPrim.Parent, textureList); + if (assetPrim.Children != null) + { + foreach (PrimObject child in assetPrim.Children) + CollectTextures(child, textureList); + } + } + + SaveTextures(new List(textureList.Keys), assetsPath, textureCacheFolder); + } + + static void CollectTextures(PrimObject prim, Dictionary textureList) + { + if (prim.Faces != null) + { + // Add all of the textures on this prim to the save list + for (int i = 0; i < prim.Faces.Length; i++) + { + PrimObject.FaceBlock face = prim.Faces[i]; + if (!textureList.ContainsKey(face.ImageID)) + textureList.Add(face.ImageID, face.ImageID); + } + } + } + + public static void SaveTextures(IList textures, string assetsPath, string textureCacheFolder) + { + int count = 0; + + // Delete the assets folder + try { Directory.Delete(assetsPath, true); } + catch (Exception) { } + + // Create a new assets folder + try { Directory.CreateDirectory(assetsPath); } + catch (Exception ex) + { + Logger.Log("Failed saving assets: " + ex.Message, Helpers.LogLevel.Error); + return; + } + + // Create a map of all of the textures in the cache + string[] files = Directory.GetFiles(textureCacheFolder, "*.texture", SearchOption.TopDirectoryOnly); + Dictionary idToFiles = new Dictionary(files.Length); + for (int i = 0; i < files.Length; i++) + { + string file = files[i]; + UUID id; + + if (UUID.TryParse(Path.GetFileNameWithoutExtension(file), out id)) + idToFiles[id] = file; + } + + for (int i = 0; i < textures.Count; i++) + { + UUID texture = textures[i]; + + if (idToFiles.ContainsKey(texture)) + { + try + { + File.Copy(idToFiles[texture], Path.Combine(assetsPath, texture.ToString() + "_texture.jp2")); + ++count; + } + catch (Exception ex) + { + Logger.Log("Failed to save texture " + texture.ToString() + ": " + ex.Message, Helpers.LogLevel.Error); + } + } + else + { + Logger.Log("Skipping missing texture " + texture.ToString(), Helpers.LogLevel.Warning); + } + } + + Logger.Log("Copied " + count + " textures to the asset archive folder", Helpers.LogLevel.Info); + } + + static void SavePrim(AssetPrim prim, string filename) + { + try + { + using (StreamWriter stream = new StreamWriter(filename)) + { + XmlTextWriter writer = new XmlTextWriter(stream); + SOGToXml2(writer, prim); + writer.Flush(); + } + } + catch (Exception ex) + { + Logger.Log("Failed saving linkset: " + ex.Message, Helpers.LogLevel.Error); + } + } + + public static void SOGToXml2(XmlTextWriter writer, AssetPrim prim) + { + writer.WriteStartElement(String.Empty, "SceneObjectGroup", String.Empty); + SOPToXml(writer, prim.Parent, null); + writer.WriteStartElement(String.Empty, "OtherParts", String.Empty); + + foreach (PrimObject child in prim.Children) + SOPToXml(writer, child, prim.Parent); + + writer.WriteEndElement(); + writer.WriteEndElement(); + } + + static void SOPToXml(XmlTextWriter writer, PrimObject prim, PrimObject parent) + { + writer.WriteStartElement("SceneObjectPart"); + writer.WriteAttributeString("xmlns:xsi", "http://www.w3.org/2001/XMLSchema-instance"); + writer.WriteAttributeString("xmlns:xsd", "http://www.w3.org/2001/XMLSchema"); + + UUID creatorID, groupID, ownerID, lastOwnerID; + UUID.TryParse(prim.CreatorIdentity, out creatorID); + UUID.TryParse(prim.GroupIdentity, out groupID); + UUID.TryParse(prim.OwnerIdentity, out ownerID); + UUID.TryParse(prim.LastOwnerIdentity, out lastOwnerID); + + WriteUUID(writer, "CreatorID", creatorID); + WriteUUID(writer, "FolderID", prim.FolderID); + writer.WriteElementString("InventorySerial", (prim.Inventory != null) ? prim.Inventory.Serial.ToString() : "0"); + + // FIXME: Task inventory + writer.WriteStartElement("TaskInventory"); writer.WriteEndElement(); + + PrimFlags flags = PrimFlags.None; + if (prim.UsePhysics) flags |= PrimFlags.Physics; + if (prim.Phantom) flags |= PrimFlags.Phantom; + if (prim.DieAtEdge) flags |= PrimFlags.DieAtEdge; + if (prim.ReturnAtEdge) flags |= PrimFlags.ReturnAtEdge; + if (prim.Temporary) flags |= PrimFlags.Temporary; + if (prim.Sandbox) flags |= PrimFlags.Sandbox; + writer.WriteElementString("ObjectFlags", ((int)flags).ToString()); + + WriteUUID(writer, "UUID", prim.ID); + writer.WriteElementString("LocalId", prim.LocalID.ToString()); + writer.WriteElementString("Name", prim.Name); + writer.WriteElementString("Material", ((int)prim.Material).ToString()); + writer.WriteElementString("RegionHandle", prim.RegionHandle.ToString()); + writer.WriteElementString("ScriptAccessPin", prim.RemoteScriptAccessPIN.ToString()); + + Vector3 groupPosition; + if (parent == null) + groupPosition = prim.Position; + else + groupPosition = parent.Position; + + WriteVector(writer, "GroupPosition", groupPosition); + if (prim.ParentID == 0) + WriteVector(writer, "OffsetPosition", Vector3.Zero); + else + WriteVector(writer, "OffsetPosition", prim.Position); + WriteQuaternion(writer, "RotationOffset", prim.Rotation); + WriteVector(writer, "Velocity", prim.Velocity); + WriteVector(writer, "RotationalVelocity", Vector3.Zero); + WriteVector(writer, "AngularVelocity", prim.AngularVelocity); + WriteVector(writer, "Acceleration", prim.Acceleration); + writer.WriteElementString("Description", prim.Description); + writer.WriteStartElement("Color"); + writer.WriteElementString("R", prim.TextColor.R.ToString(Utils.EnUsCulture)); + writer.WriteElementString("G", prim.TextColor.G.ToString(Utils.EnUsCulture)); + writer.WriteElementString("B", prim.TextColor.B.ToString(Utils.EnUsCulture)); + writer.WriteElementString("A", prim.TextColor.G.ToString(Utils.EnUsCulture)); + writer.WriteEndElement(); + writer.WriteElementString("Text", prim.Text); + writer.WriteElementString("SitName", prim.SitName); + writer.WriteElementString("TouchName", prim.TouchName); + + writer.WriteElementString("LinkNum", prim.LinkNumber.ToString()); + writer.WriteElementString("ClickAction", prim.ClickAction.ToString()); + writer.WriteStartElement("Shape"); + + writer.WriteElementString("PathBegin", Primitive.PackBeginCut(prim.Shape.PathBegin).ToString()); + writer.WriteElementString("PathCurve", prim.Shape.PathCurve.ToString()); + writer.WriteElementString("PathEnd", Primitive.PackEndCut(prim.Shape.PathEnd).ToString()); + writer.WriteElementString("PathRadiusOffset", Primitive.PackPathTwist(prim.Shape.PathRadiusOffset).ToString()); + writer.WriteElementString("PathRevolutions", Primitive.PackPathRevolutions(prim.Shape.PathRevolutions).ToString()); + writer.WriteElementString("PathScaleX", Primitive.PackPathScale(prim.Shape.PathScaleX).ToString()); + writer.WriteElementString("PathScaleY", Primitive.PackPathScale(prim.Shape.PathScaleY).ToString()); + writer.WriteElementString("PathShearX", ((byte)Primitive.PackPathShear(prim.Shape.PathShearX)).ToString()); + writer.WriteElementString("PathShearY", ((byte)Primitive.PackPathShear(prim.Shape.PathShearY)).ToString()); + writer.WriteElementString("PathSkew", Primitive.PackPathTwist(prim.Shape.PathSkew).ToString()); + writer.WriteElementString("PathTaperX", Primitive.PackPathTaper(prim.Shape.PathTaperX).ToString()); + writer.WriteElementString("PathTaperY", Primitive.PackPathTaper(prim.Shape.PathTaperY).ToString()); + writer.WriteElementString("PathTwist", Primitive.PackPathTwist(prim.Shape.PathTwist).ToString()); + writer.WriteElementString("PathTwistBegin", Primitive.PackPathTwist(prim.Shape.PathTwistBegin).ToString()); + writer.WriteElementString("PCode", prim.PCode.ToString()); + writer.WriteElementString("ProfileBegin", Primitive.PackBeginCut(prim.Shape.ProfileBegin).ToString()); + writer.WriteElementString("ProfileEnd", Primitive.PackEndCut(prim.Shape.ProfileEnd).ToString()); + writer.WriteElementString("ProfileHollow", Primitive.PackProfileHollow(prim.Shape.ProfileHollow).ToString()); + WriteVector(writer, "Scale", prim.Scale); + writer.WriteElementString("State", prim.State.ToString()); + + AssetPrim.ProfileShape shape = (AssetPrim.ProfileShape)(prim.Shape.ProfileCurve & 0x0F); + HoleType hole = (HoleType)(prim.Shape.ProfileCurve & 0xF0); + writer.WriteElementString("ProfileShape", shape.ToString()); + writer.WriteElementString("HollowShape", hole.ToString()); + writer.WriteElementString("ProfileCurve", prim.Shape.ProfileCurve.ToString()); + + writer.WriteStartElement("TextureEntry"); + + byte[] te; + if (prim.Faces != null) + te = AssetPrim.ToTextureEntry(prim.Faces).GetBytes(); + else + te = Utils.EmptyBytes; + + writer.WriteBase64(te, 0, te.Length); + writer.WriteEndElement(); + + // FIXME: ExtraParams + writer.WriteStartElement("ExtraParams"); writer.WriteEndElement(); + + writer.WriteEndElement(); + + WriteVector(writer, "Scale", prim.Scale); + writer.WriteElementString("UpdateFlag", "0"); + WriteVector(writer, "SitTargetOrientation", Vector3.UnitZ); // TODO: Is this really a vector and not a quaternion? + WriteVector(writer, "SitTargetPosition", prim.SitOffset); + WriteVector(writer, "SitTargetPositionLL", prim.SitOffset); + WriteQuaternion(writer, "SitTargetOrientationLL", prim.SitRotation); + writer.WriteElementString("ParentID", prim.ParentID.ToString()); + writer.WriteElementString("CreationDate", ((int)Utils.DateTimeToUnixTime(prim.CreationDate)).ToString()); + writer.WriteElementString("Category", "0"); + writer.WriteElementString("SalePrice", prim.SalePrice.ToString()); + writer.WriteElementString("ObjectSaleType", ((int)prim.SaleType).ToString()); + writer.WriteElementString("OwnershipCost", "0"); + WriteUUID(writer, "GroupID", groupID); + WriteUUID(writer, "OwnerID", ownerID); + WriteUUID(writer, "LastOwnerID", lastOwnerID); + writer.WriteElementString("BaseMask", ((uint)PermissionMask.All).ToString()); + writer.WriteElementString("OwnerMask", ((uint)PermissionMask.All).ToString()); + writer.WriteElementString("GroupMask", ((uint)PermissionMask.All).ToString()); + writer.WriteElementString("EveryoneMask", ((uint)PermissionMask.All).ToString()); + writer.WriteElementString("NextOwnerMask", ((uint)PermissionMask.All).ToString()); + writer.WriteElementString("Flags", "None"); + WriteUUID(writer, "SitTargetAvatar", UUID.Zero); + + writer.WriteEndElement(); + } + + static void WriteUUID(XmlTextWriter writer, string name, UUID id) + { + writer.WriteStartElement(name); + writer.WriteElementString("UUID", id.ToString()); + writer.WriteEndElement(); + } + + static void WriteVector(XmlTextWriter writer, string name, Vector3 vec) + { + writer.WriteStartElement(name); + writer.WriteElementString("X", vec.X.ToString(Utils.EnUsCulture)); + writer.WriteElementString("Y", vec.Y.ToString(Utils.EnUsCulture)); + writer.WriteElementString("Z", vec.Z.ToString(Utils.EnUsCulture)); + writer.WriteEndElement(); + } + + static void WriteQuaternion(XmlTextWriter writer, string name, Quaternion quat) + { + writer.WriteStartElement(name); + writer.WriteElementString("X", quat.X.ToString(Utils.EnUsCulture)); + writer.WriteElementString("Y", quat.Y.ToString(Utils.EnUsCulture)); + writer.WriteElementString("Z", quat.Z.ToString(Utils.EnUsCulture)); + writer.WriteElementString("W", quat.W.ToString(Utils.EnUsCulture)); + writer.WriteEndElement(); + } + + #endregion Archive Saving + } +} diff --git a/OpenMetaverse/Assets/Archiving/TarArchiveReader.cs b/OpenMetaverse/Assets/Archiving/TarArchiveReader.cs new file mode 100644 index 00000000..efd911d4 --- /dev/null +++ b/OpenMetaverse/Assets/Archiving/TarArchiveReader.cs @@ -0,0 +1,214 @@ +/* + * Copyright (c) 2009, openmetaverse.org + * All rights reserved. + * + * - 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. + * - Neither the name of the openmetaverse.org 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 COPYRIGHT HOLDERS AND CONTRIBUTORS "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 COPYRIGHT OWNER OR 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 System; +using System.IO; +using System.Reflection; +using System.Text; + +namespace OpenMetaverse.Assets +{ + /// + /// Temporary code to do the bare minimum required to read a tar archive for our purposes + /// + public class TarArchiveReader + { + public enum TarEntryType + { + TYPE_UNKNOWN = 0, + TYPE_NORMAL_FILE = 1, + TYPE_HARD_LINK = 2, + TYPE_SYMBOLIC_LINK = 3, + TYPE_CHAR_SPECIAL = 4, + TYPE_BLOCK_SPECIAL = 5, + TYPE_DIRECTORY = 6, + TYPE_FIFO = 7, + TYPE_CONTIGUOUS_FILE = 8, + } + + protected static ASCIIEncoding m_asciiEncoding = new ASCIIEncoding(); + + /// + /// Binary reader for the underlying stream + /// + protected BinaryReader m_br; + + /// + /// Used to trim off null chars + /// + protected char[] m_nullCharArray = new char[] { '\0' }; + + /// + /// Generate a tar reader which reads from the given stream. + /// + /// + public TarArchiveReader(Stream s) + { + m_br = new BinaryReader(s); + } + + /// + /// Read the next entry in the tar file. + /// + /// + /// the data for the entry. Returns null if there are no more entries + public byte[] ReadEntry(out string filePath, out TarEntryType entryType) + { + filePath = String.Empty; + entryType = TarEntryType.TYPE_UNKNOWN; + TarHeader header = ReadHeader(); + + if (null == header) + return null; + + entryType = header.EntryType; + filePath = header.FilePath; + return ReadData(header.FileSize); + } + + /// + /// Read the next 512 byte chunk of data as a tar header. + /// + /// A tar header struct. null if we have reached the end of the archive. + protected TarHeader ReadHeader() + { + byte[] header = m_br.ReadBytes(512); + + // If we've reached the end of the archive we'll be in null block territory, which means + // the next byte will be 0 + if (header[0] == 0) + return null; + + TarHeader tarHeader = new TarHeader(); + + // If we're looking at a GNU tar long link then extract the long name and pull up the next header + if (header[156] == (byte)'L') + { + int longNameLength = ConvertOctalBytesToDecimal(header, 124, 11); + tarHeader.FilePath = m_asciiEncoding.GetString(ReadData(longNameLength)); + //m_log.DebugFormat("[TAR ARCHIVE READER]: Got long file name {0}", tarHeader.FilePath); + header = m_br.ReadBytes(512); + } + else + { + tarHeader.FilePath = m_asciiEncoding.GetString(header, 0, 100); + tarHeader.FilePath = tarHeader.FilePath.Trim(m_nullCharArray); + //m_log.DebugFormat("[TAR ARCHIVE READER]: Got short file name {0}", tarHeader.FilePath); + } + + tarHeader.FileSize = ConvertOctalBytesToDecimal(header, 124, 11); + + switch (header[156]) + { + case 0: + tarHeader.EntryType = TarEntryType.TYPE_NORMAL_FILE; + break; + case (byte)'0': + tarHeader.EntryType = TarEntryType.TYPE_NORMAL_FILE; + break; + case (byte)'1': + tarHeader.EntryType = TarEntryType.TYPE_HARD_LINK; + break; + case (byte)'2': + tarHeader.EntryType = TarEntryType.TYPE_SYMBOLIC_LINK; + break; + case (byte)'3': + tarHeader.EntryType = TarEntryType.TYPE_CHAR_SPECIAL; + break; + case (byte)'4': + tarHeader.EntryType = TarEntryType.TYPE_BLOCK_SPECIAL; + break; + case (byte)'5': + tarHeader.EntryType = TarEntryType.TYPE_DIRECTORY; + break; + case (byte)'6': + tarHeader.EntryType = TarEntryType.TYPE_FIFO; + break; + case (byte)'7': + tarHeader.EntryType = TarEntryType.TYPE_CONTIGUOUS_FILE; + break; + } + + return tarHeader; + } + + /// + /// Read data following a header + /// + /// + /// + protected byte[] ReadData(int fileSize) + { + byte[] data = m_br.ReadBytes(fileSize); + + //m_log.DebugFormat("[TAR ARCHIVE READER]: fileSize {0}", fileSize); + + // Read the rest of the empty padding in the 512 byte block + if (fileSize % 512 != 0) + { + int paddingLeft = 512 - (fileSize % 512); + + //m_log.DebugFormat("[TAR ARCHIVE READER]: Reading {0} padding bytes", paddingLeft); + + m_br.ReadBytes(paddingLeft); + } + + return data; + } + + public void Close() + { + m_br.Close(); + } + + /// + /// Convert octal bytes to a decimal representation + /// + /// + /// + public static int ConvertOctalBytesToDecimal(byte[] bytes, int startIndex, int count) + { + string oString = m_asciiEncoding.GetString(bytes, startIndex, count); + + int d = 0; + + foreach (char c in oString) + { + d <<= 3; + d |= c - '0'; + } + + return d; + } + } + + public class TarHeader + { + public string FilePath; + public int FileSize; + public TarArchiveReader.TarEntryType EntryType; + } +} diff --git a/OpenMetaverse/Assets/Archiving/TarArchiveWriter.cs b/OpenMetaverse/Assets/Archiving/TarArchiveWriter.cs new file mode 100644 index 00000000..6da6091f --- /dev/null +++ b/OpenMetaverse/Assets/Archiving/TarArchiveWriter.cs @@ -0,0 +1,214 @@ +/* + * Copyright (c) 2009, openmetaverse.org + * All rights reserved. + * + * - 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. + * - Neither the name of the openmetaverse.org 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 COPYRIGHT HOLDERS AND CONTRIBUTORS "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 COPYRIGHT OWNER OR 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 System; +using System.Collections.Generic; +using System.IO; +using System.Text; + +namespace OpenMetaverse.Assets +{ + /// + /// Temporary code to produce a tar archive in tar v7 format + /// + public class TarArchiveWriter + { + protected static ASCIIEncoding m_asciiEncoding = new ASCIIEncoding(); + + /// + /// Binary writer for the underlying stream + /// + protected BinaryWriter m_bw; + + public TarArchiveWriter(Stream s) + { + m_bw = new BinaryWriter(s); + } + + /// + /// Write a directory entry to the tar archive. We can only handle one path level right now! + /// + /// + public void WriteDir(string dirName) + { + // Directories are signalled by a final / + if (!dirName.EndsWith("/")) + dirName += "/"; + + WriteFile(dirName, new byte[0]); + } + + /// + /// Write a file to the tar archive + /// + /// + /// + public void WriteFile(string filePath, string data) + { + WriteFile(filePath, m_asciiEncoding.GetBytes(data)); + } + + /// + /// Write a file to the tar archive + /// + /// + /// + public void WriteFile(string filePath, byte[] data) + { + if (filePath.Length > 100) + WriteEntry("././@LongLink", m_asciiEncoding.GetBytes(filePath), 'L'); + + char fileType; + + if (filePath.EndsWith("/")) + { + fileType = '5'; + } + else + { + fileType = '0'; + } + + WriteEntry(filePath, data, fileType); + } + + /// + /// Finish writing the raw tar archive data to a stream. The stream will be closed on completion. + /// + /// Stream to which to write the data + /// + public void Close() + { + //m_log.Debug("[TAR ARCHIVE WRITER]: Writing final consecutive 0 blocks"); + + // Write two consecutive 0 blocks to end the archive + byte[] finalZeroPadding = new byte[1024]; + m_bw.Write(finalZeroPadding); + + m_bw.Flush(); + m_bw.Close(); + } + + public static byte[] ConvertDecimalToPaddedOctalBytes(int d, int padding) + { + string oString = ""; + + while (d > 0) + { + oString = Convert.ToString((byte)'0' + d & 7) + oString; + d >>= 3; + } + + while (oString.Length < padding) + { + oString = "0" + oString; + } + + byte[] oBytes = m_asciiEncoding.GetBytes(oString); + + return oBytes; + } + + /// + /// Write a particular entry + /// + /// + /// + /// + protected void WriteEntry(string filePath, byte[] data, char fileType) + { + byte[] header = new byte[512]; + + // file path field (100) + byte[] nameBytes = m_asciiEncoding.GetBytes(filePath); + int nameSize = (nameBytes.Length >= 100) ? 100 : nameBytes.Length; + Array.Copy(nameBytes, header, nameSize); + + // file mode (8) + byte[] modeBytes = m_asciiEncoding.GetBytes("0000777"); + Array.Copy(modeBytes, 0, header, 100, 7); + + // owner user id (8) + byte[] ownerIdBytes = m_asciiEncoding.GetBytes("0000764"); + Array.Copy(ownerIdBytes, 0, header, 108, 7); + + // group user id (8) + byte[] groupIdBytes = m_asciiEncoding.GetBytes("0000764"); + Array.Copy(groupIdBytes, 0, header, 116, 7); + + // file size in bytes (12) + int fileSize = data.Length; + //m_log.DebugFormat("[TAR ARCHIVE WRITER]: File size of {0} is {1}", filePath, fileSize); + + byte[] fileSizeBytes = ConvertDecimalToPaddedOctalBytes(fileSize, 11); + + Array.Copy(fileSizeBytes, 0, header, 124, 11); + + // last modification time (12) + byte[] lastModTimeBytes = m_asciiEncoding.GetBytes("11017037332"); + Array.Copy(lastModTimeBytes, 0, header, 136, 11); + + // entry type indicator (1) + header[156] = m_asciiEncoding.GetBytes(new char[] { fileType })[0]; + + Array.Copy(m_asciiEncoding.GetBytes("0000000"), 0, header, 329, 7); + Array.Copy(m_asciiEncoding.GetBytes("0000000"), 0, header, 337, 7); + + // check sum for header block (8) [calculated last] + Array.Copy(m_asciiEncoding.GetBytes(" "), 0, header, 148, 8); + + int checksum = 0; + foreach (byte b in header) + { + checksum += b; + } + + //m_log.DebugFormat("[TAR ARCHIVE WRITER]: Decimal header checksum is {0}", checksum); + + byte[] checkSumBytes = ConvertDecimalToPaddedOctalBytes(checksum, 6); + + Array.Copy(checkSumBytes, 0, header, 148, 6); + + header[154] = 0; + + // Write out header + m_bw.Write(header); + + // Write out data + m_bw.Write(data); + + if (data.Length % 512 != 0) + { + int paddingRequired = 512 - (data.Length % 512); + + //m_log.DebugFormat("[TAR ARCHIVE WRITER]: Padding data with {0} bytes", paddingRequired); + + byte[] padding = new byte[paddingRequired]; + m_bw.Write(padding); + } + } + } +} diff --git a/OpenMetaverse/Assets/Asset.cs b/OpenMetaverse/Assets/Asset.cs new file mode 100644 index 00000000..468c9873 --- /dev/null +++ b/OpenMetaverse/Assets/Asset.cs @@ -0,0 +1,87 @@ +/* + * Copyright (c) 2009, openmetaverse.org + * All rights reserved. + * + * - 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. + * - Neither the name of the openmetaverse.org 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 COPYRIGHT HOLDERS AND CONTRIBUTORS "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 COPYRIGHT OWNER OR 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 System; +using OpenMetaverse; + +namespace OpenMetaverse.Assets +{ + /// + /// Base class for all Asset types + /// + public abstract class Asset + { + /// A byte array containing the raw asset data + public byte[] AssetData; + /// True if the asset it only stored on the server temporarily + public bool Temporary; + /// A unique ID + private UUID _AssetID; + /// The assets unique ID + public UUID AssetID + { + get { return _AssetID; } + internal set { _AssetID = value; } + } + + /// + /// The "type" of asset, Notecard, Animation, etc + /// + public abstract AssetType AssetType + { + get; + } + + /// + /// Construct a new Asset object + /// + public Asset() { } + + /// + /// Construct a new Asset object + /// + /// A unique specific to this asset + /// A byte array containing the raw asset data + public Asset(UUID assetID, byte[] assetData) + { + _AssetID = assetID; + AssetData = assetData; + } + + /// + /// Regenerates the AssetData byte array from the properties + /// of the derived class. + /// + public abstract void Encode(); + + /// + /// Decodes the AssetData, placing it in appropriate properties of the derived + /// class. + /// + /// True if the asset decoding succeeded, otherwise false + public abstract bool Decode(); + } +} diff --git a/OpenMetaverse/Assets/AssetTypes/AssetAnimation.cs b/OpenMetaverse/Assets/AssetTypes/AssetAnimation.cs new file mode 100644 index 00000000..f9b54733 --- /dev/null +++ b/OpenMetaverse/Assets/AssetTypes/AssetAnimation.cs @@ -0,0 +1,57 @@ +/* + * Copyright (c) 2009, openmetaverse.org + * All rights reserved. + * + * - 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. + * - Neither the name of the openmetaverse.org 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 COPYRIGHT HOLDERS AND CONTRIBUTORS "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 COPYRIGHT OWNER OR 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 System; +using OpenMetaverse; + +namespace OpenMetaverse.Assets +{ + /// + /// Represents an Animation + /// + public class AssetAnimation : Asset + { + /// Override the base classes AssetType + public override AssetType AssetType { get { return AssetType.Animation; } } + + /// Default Constructor + public AssetAnimation() { } + + /// + /// Construct an Asset object of type Animation + /// + /// A unique specific to this asset + /// A byte array containing the raw asset data + public AssetAnimation(UUID assetID, byte[] assetData) + : base(assetID, assetData) + { + AssetData = assetData; + } + + public override void Encode() { } + public override bool Decode() { return true; } + } +} diff --git a/OpenMetaverse/Assets/AssetTypes/AssetBodypart.cs b/OpenMetaverse/Assets/AssetTypes/AssetBodypart.cs new file mode 100644 index 00000000..d092d946 --- /dev/null +++ b/OpenMetaverse/Assets/AssetTypes/AssetBodypart.cs @@ -0,0 +1,52 @@ +/* + * Copyright (c) 2009, openmetaverse.org + * All rights reserved. + * + * - 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. + * - Neither the name of the openmetaverse.org 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 COPYRIGHT HOLDERS AND CONTRIBUTORS "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 COPYRIGHT OWNER OR 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 System; +using OpenMetaverse; + +namespace OpenMetaverse.Assets +{ + /// + /// Represents an that represents an avatars body ie: Hair, Etc. + /// + public class AssetBodypart : AssetWearable + { + /// Override the base classes AssetType + public override AssetType AssetType { get { return AssetType.Bodypart; } } + + /// Initializes a new instance of an AssetBodyPart object + public AssetBodypart() { } + + /// Initializes a new instance of an AssetBodyPart object with parameters + /// A unique specific to this asset + /// A byte array containing the raw asset data + public AssetBodypart(UUID assetID, byte[] assetData) : base(assetID, assetData) { } + + /// Initializes a new instance of an AssetBodyPart object with parameters + /// A string representing the values of the Bodypart + public AssetBodypart(string source) : base(source) { } + } +} diff --git a/OpenMetaverse/Assets/AssetTypes/AssetClothing.cs b/OpenMetaverse/Assets/AssetTypes/AssetClothing.cs new file mode 100644 index 00000000..ad6ecb45 --- /dev/null +++ b/OpenMetaverse/Assets/AssetTypes/AssetClothing.cs @@ -0,0 +1,53 @@ +/* + * Copyright (c) 2009, openmetaverse.org + * All rights reserved. + * + * - 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. + * - Neither the name of the openmetaverse.org 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 COPYRIGHT HOLDERS AND CONTRIBUTORS "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 COPYRIGHT OWNER OR 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 System; +using OpenMetaverse; + +namespace OpenMetaverse.Assets +{ + /// + /// Represents an that can be worn on an avatar + /// such as a Shirt, Pants, etc. + /// + public class AssetClothing : AssetWearable + { + /// Override the base classes AssetType + public override AssetType AssetType { get { return AssetType.Clothing; } } + + /// Initializes a new instance of an AssetScriptBinary object + public AssetClothing() { } + + /// Initializes a new instance of an AssetScriptBinary object with parameters + /// A unique specific to this asset + /// A byte array containing the raw asset data + public AssetClothing(UUID assetID, byte[] assetData) : base(assetID, assetData) { } + + /// Initializes a new instance of an AssetScriptBinary object with parameters + /// A string containing the Clothings data + public AssetClothing(string source) : base(source) { } + } +} diff --git a/OpenMetaverse/Assets/AssetTypes/AssetLandmark.cs b/OpenMetaverse/Assets/AssetTypes/AssetLandmark.cs new file mode 100644 index 00000000..02bec33f --- /dev/null +++ b/OpenMetaverse/Assets/AssetTypes/AssetLandmark.cs @@ -0,0 +1,103 @@ +/* + * Copyright (c) 2009, openmetaverse.org + * All rights reserved. + * + * - 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. + * - Neither the name of the openmetaverse.org 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 COPYRIGHT HOLDERS AND CONTRIBUTORS "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 COPYRIGHT OWNER OR 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 System; +using OpenMetaverse; + +namespace OpenMetaverse.Assets +{ + /// + /// Represents a Landmark with RegionID and Position vector + /// + public class AssetLandmark : Asset + { + /// Override the base classes AssetType + public override AssetType AssetType { get { return AssetType.Landmark; } } + + /// UUID of the Landmark target region + public UUID RegionID = UUID.Zero; + /// Local position of the target + public Vector3 Position = Vector3.Zero; + + /// Construct an Asset of type Landmark + public AssetLandmark() { } + + /// + /// Construct an Asset object of type Landmark + /// + /// A unique specific to this asset + /// A byte array containing the raw asset data + public AssetLandmark(UUID assetID, byte[] assetData) + : base(assetID, assetData) + { + Decode(); + } + + /// + /// Constuct an asset of type Landmark + /// + /// UUID of the target region + /// Local position of landmark + public AssetLandmark(UUID regionID, Vector3 pos) + { + RegionID = regionID; + Position = pos; + Encode(); + } + + /// + /// Encode the raw contents of a string with the specific Landmark format + /// + public override void Encode() + { + string temp = "Landmark version 2\n"; + temp += "region_id " + RegionID + "\n"; + temp += String.Format("local_pos {0:0.00} {1:0.00} {2:0.00}\n", Position.X, Position.Y, Position.Z); + AssetData = Utils.StringToBytes(temp); + } + + /// + /// Decode the raw asset data, populating the RegionID and Position + /// + /// true if the AssetData was successfully decoded to a UUID and Vector + public override bool Decode() + { + String text = Utils.BytesToString(AssetData); + if (text.ToLower().Contains("landmark version 2")) + { + RegionID = new UUID(text.Substring(text.IndexOf("region_id") + 10, 36)); + String vecDelim = " "; + String[] vecStrings = text.Substring(text.IndexOf("local_pos") + 10).Split(vecDelim.ToCharArray()); + if (vecStrings.Length == 3) + { + Position = new Vector3(float.Parse(vecStrings[0]), float.Parse(vecStrings[1]), float.Parse(vecStrings[2])); + return true; + } + } + return false; + } + } +} diff --git a/OpenMetaverse/Assets/AssetTypes/AssetNotecard.cs b/OpenMetaverse/Assets/AssetTypes/AssetNotecard.cs new file mode 100644 index 00000000..14389648 --- /dev/null +++ b/OpenMetaverse/Assets/AssetTypes/AssetNotecard.cs @@ -0,0 +1,89 @@ +/* + * Copyright (c) 2009, openmetaverse.org + * All rights reserved. + * + * - 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. + * - Neither the name of the openmetaverse.org 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 COPYRIGHT HOLDERS AND CONTRIBUTORS "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 COPYRIGHT OWNER OR 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 System; +using OpenMetaverse; + +namespace OpenMetaverse.Assets +{ + /// + /// Represents a string of characters encoded with specific formatting properties + /// + public class AssetNotecard : Asset + { + /// Override the base classes AssetType + public override AssetType AssetType { get { return AssetType.Notecard; } } + + /// A text string containing the raw contents of the notecard + public string Text = null; + + /// Construct an Asset of type Notecard + public AssetNotecard() { } + + /// + /// Construct an Asset object of type Notecard + /// + /// A unique specific to this asset + /// A byte array containing the raw asset data + public AssetNotecard(UUID assetID, byte[] assetData) + : base(assetID, assetData) + { + Decode(); + } + + /// + /// Construct an Asset object of type Notecard + /// + /// A text string containing the raw contents of the notecard + public AssetNotecard(string text) + { + Text = text; + Encode(); + } + + /// + /// Encode the raw contents of a string with the specific Linden Text properties + /// + public override void Encode() + { + string temp = "Linden text version 2\n{\nLLEmbeddedItems version 1\n{\ncount 0\n}\nText length "; + temp += Text.Length + "\n"; + temp += Text; + temp += "}"; + AssetData = Utils.StringToBytes(temp); + } + + /// + /// Decode the raw asset data including the Linden Text properties + /// + /// true if the AssetData was successfully decoded to a string + public override bool Decode() + { + Text = Utils.BytesToString(AssetData); + return true; + } + } +} diff --git a/OpenMetaverse/Assets/AssetTypes/AssetPrim.cs b/OpenMetaverse/Assets/AssetTypes/AssetPrim.cs new file mode 100644 index 00000000..d2ce7f94 --- /dev/null +++ b/OpenMetaverse/Assets/AssetTypes/AssetPrim.cs @@ -0,0 +1,989 @@ +/* + * Copyright (c) 2009, openmetaverse.org + * All rights reserved. + * + * - 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. + * - Neither the name of the openmetaverse.org 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 COPYRIGHT HOLDERS AND CONTRIBUTORS "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 COPYRIGHT OWNER OR 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 System; +using System.Collections.Generic; +using System.IO; +using System.Xml; +using OpenMetaverse; +using OpenMetaverse.StructuredData; + +namespace OpenMetaverse.Assets +{ + /// + /// Represents a primitive asset + /// + public class AssetPrim : Asset + { + /// + /// Only used internally for XML serialization/deserialization + /// + internal enum ProfileShape : byte + { + Circle = 0, + Square = 1, + IsometricTriangle = 2, + EquilateralTriangle = 3, + RightTriangle = 4, + HalfCircle = 5 + } + + public PrimObject Parent; + public List Children; + + /// Override the base classes AssetType + public override AssetType AssetType { get { return AssetType.Object; } } + + /// Initializes a new instance of an AssetPrim object + public AssetPrim() { } + + public AssetPrim(string xmlData) + { + DecodeXml(xmlData); + } + + public AssetPrim(PrimObject parent, List children) + { + Parent = parent; + if (children != null) + Children = children; + else + Children = new List(0); + } + + /// + /// + /// + public override void Encode() + { + // FIXME: + } + + /// + /// + /// + /// + public override bool Decode() + { + // FIXME: + return false; + } + + public string EncodeXml() + { + TextWriter textWriter = new StringWriter(); + XmlTextWriter xmlWriter = new XmlTextWriter(textWriter); + OarFile.SOGToXml2(xmlWriter, this); + xmlWriter.Flush(); + return textWriter.ToString(); + } + + public bool DecodeXml(string xmlData) + { + using (XmlTextReader reader = new XmlTextReader(new StringReader(xmlData))) + { + reader.Read(); + reader.ReadStartElement("SceneObjectGroup"); + Parent = LoadPrim(reader); + + if (Parent != null) + { + List children = new List(); + + reader.Read(); + + while (!reader.EOF) + { + switch (reader.NodeType) + { + case XmlNodeType.Element: + if (reader.Name == "SceneObjectPart") + { + PrimObject child = LoadPrim(reader); + if (child != null) + children.Add(child); + } + else + { + Logger.Log("Found unexpected prim XML element " + reader.Name, Helpers.LogLevel.Warning); + reader.Read(); + } + break; + case XmlNodeType.EndElement: + reader.Read(); + break; + } + } + + Children = children; + return true; + } + else + { + Logger.Log("Failed to load root linkset prim", Helpers.LogLevel.Error); + return false; + } + } + } + + public static PrimObject LoadPrim(XmlTextReader reader) + { + PrimObject obj = new PrimObject(); + obj.Shape = new PrimObject.ShapeBlock(); + obj.Inventory = new PrimObject.InventoryBlock(); + + reader.ReadStartElement("SceneObjectPart"); + obj.CreatorIdentity = ReadUUID(reader, "CreatorID").ToString(); + UUID folderID = ReadUUID(reader, "FolderID"); + obj.Inventory.Serial = reader.ReadElementContentAsInt("InventorySerial", String.Empty); + + // FIXME: Parse TaskInventory + obj.Inventory.Items = new PrimObject.InventoryBlock.ItemBlock[0]; + reader.ReadInnerXml(); + + PrimFlags flags = (PrimFlags)reader.ReadElementContentAsInt("ObjectFlags", String.Empty); + obj.UsePhysics = (flags & PrimFlags.Physics) != 0; + obj.Phantom = (flags & PrimFlags.Phantom) != 0; + obj.DieAtEdge = (flags & PrimFlags.DieAtEdge) != 0; + obj.ReturnAtEdge = (flags & PrimFlags.ReturnAtEdge) != 0; + obj.Temporary = (flags & PrimFlags.Temporary) != 0; + obj.Sandbox = (flags & PrimFlags.Sandbox) != 0; + + obj.ID = ReadUUID(reader, "UUID"); + obj.LocalID = (uint)reader.ReadElementContentAsLong("LocalId", String.Empty); + obj.Name = reader.ReadElementString("Name"); + obj.Material = reader.ReadElementContentAsInt("Material", String.Empty); + + reader.ReadInnerXml(); // RegionHandle + + obj.RemoteScriptAccessPIN = reader.ReadElementContentAsInt("ScriptAccessPin", String.Empty); + + Vector3 groupPosition = ReadVector(reader, "GroupPosition"); + Vector3 offsetPosition = ReadVector(reader, "OffsetPosition"); + obj.Rotation = ReadQuaternion(reader, "RotationOffset"); + obj.Velocity = ReadVector(reader, "Velocity"); + Vector3 rotationalVelocity = ReadVector(reader, "RotationalVelocity"); + obj.AngularVelocity = ReadVector(reader, "AngularVelocity"); + obj.Acceleration = ReadVector(reader, "Acceleration"); + obj.Description = reader.ReadElementString("Description"); + reader.ReadStartElement("Color"); + if (reader.Name == "R") + { + obj.TextColor.R = reader.ReadElementContentAsFloat("R", String.Empty); + obj.TextColor.G = reader.ReadElementContentAsFloat("G", String.Empty); + obj.TextColor.B = reader.ReadElementContentAsFloat("B", String.Empty); + obj.TextColor.A = reader.ReadElementContentAsFloat("A", String.Empty); + reader.ReadEndElement(); + } + obj.Text = reader.ReadElementString("Text", String.Empty); + obj.SitName = reader.ReadElementString("SitName", String.Empty); + obj.TouchName = reader.ReadElementString("TouchName", String.Empty); + + obj.LinkNumber = reader.ReadElementContentAsInt("LinkNum", String.Empty); + obj.ClickAction = reader.ReadElementContentAsInt("ClickAction", String.Empty); + + reader.ReadStartElement("Shape"); + obj.Shape.ProfileCurve = reader.ReadElementContentAsInt("ProfileCurve", String.Empty); + + byte[] teData = Convert.FromBase64String(reader.ReadElementString("TextureEntry")); + Primitive.TextureEntry te = new Primitive.TextureEntry(teData, 0, teData.Length); + obj.Faces = FromTextureEntry(te); + + reader.ReadInnerXml(); // ExtraParams + + obj.Shape.PathBegin = Primitive.UnpackBeginCut((ushort)reader.ReadElementContentAsInt("PathBegin", String.Empty)); + obj.Shape.PathCurve = reader.ReadElementContentAsInt("PathCurve", String.Empty); + obj.Shape.PathEnd = Primitive.UnpackEndCut((ushort)reader.ReadElementContentAsInt("PathEnd", String.Empty)); + obj.Shape.PathRadiusOffset = Primitive.UnpackPathTwist((sbyte)reader.ReadElementContentAsInt("PathRadiusOffset", String.Empty)); + obj.Shape.PathRevolutions = Primitive.UnpackPathRevolutions((byte)reader.ReadElementContentAsInt("PathRevolutions", String.Empty)); + obj.Shape.PathScaleX = Primitive.UnpackPathScale((byte)reader.ReadElementContentAsInt("PathScaleX", String.Empty)); + obj.Shape.PathScaleY = Primitive.UnpackPathScale((byte)reader.ReadElementContentAsInt("PathScaleY", String.Empty)); + obj.Shape.PathShearX = Primitive.UnpackPathShear((sbyte)reader.ReadElementContentAsInt("PathShearX", String.Empty)); + obj.Shape.PathShearY = Primitive.UnpackPathShear((sbyte)reader.ReadElementContentAsInt("PathShearY", String.Empty)); + obj.Shape.PathSkew = Primitive.UnpackPathTwist((sbyte)reader.ReadElementContentAsInt("PathSkew", String.Empty)); + obj.Shape.PathTaperX = Primitive.UnpackPathTaper((sbyte)reader.ReadElementContentAsInt("PathTaperX", String.Empty)); + obj.Shape.PathTaperY = Primitive.UnpackPathShear((sbyte)reader.ReadElementContentAsInt("PathTaperY", String.Empty)); + obj.Shape.PathTwist = Primitive.UnpackPathTwist((sbyte)reader.ReadElementContentAsInt("PathTwist", String.Empty)); + obj.Shape.PathTwistBegin = Primitive.UnpackPathTwist((sbyte)reader.ReadElementContentAsInt("PathTwistBegin", String.Empty)); + obj.PCode = reader.ReadElementContentAsInt("PCode", String.Empty); + obj.Shape.ProfileBegin = Primitive.UnpackBeginCut((ushort)reader.ReadElementContentAsInt("ProfileBegin", String.Empty)); + obj.Shape.ProfileEnd = Primitive.UnpackEndCut((ushort)reader.ReadElementContentAsInt("ProfileEnd", String.Empty)); + obj.Shape.ProfileHollow = Primitive.UnpackProfileHollow((ushort)reader.ReadElementContentAsInt("ProfileHollow", String.Empty)); + obj.Scale = ReadVector(reader, "Scale"); + obj.State = (byte)reader.ReadElementContentAsInt("State", String.Empty); + + ProfileShape profileShape = (ProfileShape)Enum.Parse(typeof(ProfileShape), reader.ReadElementString("ProfileShape")); + HoleType holeType = (HoleType)Enum.Parse(typeof(HoleType), reader.ReadElementString("HollowShape")); + obj.Shape.ProfileCurve = (int)profileShape | (int)holeType; + + UUID sculptTexture = ReadUUID(reader, "SculptTexture"); + SculptType sculptType = (SculptType)reader.ReadElementContentAsInt("SculptType", String.Empty); + if (sculptTexture != UUID.Zero) + { + obj.Sculpt = new PrimObject.SculptBlock(); + obj.Sculpt.Texture = sculptTexture; + obj.Sculpt.Type = (int)sculptType; + } + + PrimObject.FlexibleBlock flexible = new PrimObject.FlexibleBlock(); + PrimObject.LightBlock light = new PrimObject.LightBlock(); + + reader.ReadInnerXml(); // SculptData + + flexible.Softness = reader.ReadElementContentAsInt("FlexiSoftness", String.Empty); + flexible.Tension = reader.ReadElementContentAsFloat("FlexiTension", String.Empty); + flexible.Drag = reader.ReadElementContentAsFloat("FlexiDrag", String.Empty); + flexible.Gravity = reader.ReadElementContentAsFloat("FlexiGravity", String.Empty); + flexible.Wind = reader.ReadElementContentAsFloat("FlexiWind", String.Empty); + flexible.Force.X = reader.ReadElementContentAsFloat("FlexiForceX", String.Empty); + flexible.Force.Y = reader.ReadElementContentAsFloat("FlexiForceY", String.Empty); + flexible.Force.Z = reader.ReadElementContentAsFloat("FlexiForceZ", String.Empty); + + light.Color.R = reader.ReadElementContentAsFloat("LightColorR", String.Empty); + light.Color.G = reader.ReadElementContentAsFloat("LightColorG", String.Empty); + light.Color.B = reader.ReadElementContentAsFloat("LightColorB", String.Empty); + light.Color.A = reader.ReadElementContentAsFloat("LightColorA", String.Empty); + light.Radius = reader.ReadElementContentAsFloat("LightRadius", String.Empty); + light.Cutoff = reader.ReadElementContentAsFloat("LightCutoff", String.Empty); + light.Falloff = reader.ReadElementContentAsFloat("LightFalloff", String.Empty); + light.Intensity = reader.ReadElementContentAsFloat("LightIntensity", String.Empty); + + reader.ReadInnerXml(); // FlexiTension + reader.ReadInnerXml(); // FlexiDrag + reader.ReadInnerXml(); // FlexiGravity + reader.ReadInnerXml(); // FlexiWind + reader.ReadInnerXml(); // FlexiForceX + reader.ReadInnerXml(); // FlexiForceY + reader.ReadInnerXml(); // FlexiForceZ + reader.ReadInnerXml(); // LightColorR + reader.ReadInnerXml(); // LightColorG + reader.ReadInnerXml(); // LightColorB + reader.ReadInnerXml(); // LightColorA + reader.ReadInnerXml(); // LightRadius + reader.ReadInnerXml(); // LightCutoff + reader.ReadInnerXml(); // LightFalloff + reader.ReadInnerXml(); // LightIntensity + bool hasFlexi = reader.ReadElementContentAsBoolean("FlexiEntry", String.Empty); + bool hasLight = reader.ReadElementContentAsBoolean("LightEntry", String.Empty); + reader.ReadInnerXml(); // SculptEntry + + if (hasFlexi) + obj.Flexible = flexible; + if (hasLight) + obj.Light = light; + + reader.ReadEndElement(); + + obj.Scale = ReadVector(reader, "Scale"); // Yes, again + reader.ReadInnerXml(); // UpdateFlag + + reader.ReadInnerXml(); // SitTargetOrientation + reader.ReadInnerXml(); // SitTargetPosition + obj.SitOffset = ReadVector(reader, "SitTargetPositionLL"); + obj.SitRotation = ReadQuaternion(reader, "SitTargetOrientationLL"); + obj.ParentID = (uint)reader.ReadElementContentAsLong("ParentID", String.Empty); + obj.CreationDate = Utils.UnixTimeToDateTime(reader.ReadElementContentAsInt("CreationDate", String.Empty)); + //obj.Category = reader.ReadElementContentAsInt("Category", String.Empty); + int category = reader.ReadElementContentAsInt("Category", String.Empty); + obj.SalePrice = reader.ReadElementContentAsInt("SalePrice", String.Empty); + obj.SaleType = reader.ReadElementContentAsInt("ObjectSaleType", String.Empty); + int ownershipCost = reader.ReadElementContentAsInt("OwnershipCost", String.Empty); + obj.GroupIdentity = ReadUUID(reader, "GroupID").ToString(); + obj.OwnerIdentity = ReadUUID(reader, "OwnerID").ToString(); + obj.LastOwnerIdentity = ReadUUID(reader, "LastOwnerID").ToString(); + obj.PermsBase = (uint)reader.ReadElementContentAsInt("BaseMask", String.Empty); + obj.PermsOwner = (uint)reader.ReadElementContentAsInt("OwnerMask", String.Empty); + obj.PermsGroup = (uint)reader.ReadElementContentAsInt("GroupMask", String.Empty); + obj.PermsEveryone = (uint)reader.ReadElementContentAsInt("EveryoneMask", String.Empty); + obj.PermsNextOwner = (uint)reader.ReadElementContentAsInt("NextOwnerMask", String.Empty); + + reader.ReadInnerXml(); // Flags + reader.ReadInnerXml(); // CollisionSound + reader.ReadInnerXml(); // CollisionSoundVolume + + reader.ReadEndElement(); + + if (obj.ParentID == 0) + obj.Position = groupPosition; + else + obj.Position = offsetPosition; + + return obj; + } + + public static PrimObject.FaceBlock[] FromTextureEntry(Primitive.TextureEntry te) + { + // FIXME: + return new PrimObject.FaceBlock[0]; + } + + public static Primitive.TextureEntry ToTextureEntry(PrimObject.FaceBlock[] faces) + { + // FIXME: + return new Primitive.TextureEntry(UUID.Zero); + } + + static UUID ReadUUID(XmlTextReader reader, string name) + { + UUID id; + string idStr; + + reader.ReadStartElement(name); + + if (reader.Name == "Guid") + idStr = reader.ReadElementString("Guid"); + else // UUID + idStr = reader.ReadElementString("UUID"); + + UUID.TryParse(idStr, out id); + reader.ReadEndElement(); + + return id; + } + + static Vector3 ReadVector(XmlTextReader reader, string name) + { + Vector3 vec; + + reader.ReadStartElement(name); + vec.X = reader.ReadElementContentAsFloat("X", String.Empty); + vec.Y = reader.ReadElementContentAsFloat("Y", String.Empty); + vec.Z = reader.ReadElementContentAsFloat("Z", String.Empty); + reader.ReadEndElement(); + + return vec; + } + + static Quaternion ReadQuaternion(XmlTextReader reader, string name) + { + Quaternion quat; + + reader.ReadStartElement(name); + quat.X = reader.ReadElementContentAsFloat("X", String.Empty); + quat.Y = reader.ReadElementContentAsFloat("Y", String.Empty); + quat.Z = reader.ReadElementContentAsFloat("Z", String.Empty); + quat.W = reader.ReadElementContentAsFloat("W", String.Empty); + reader.ReadEndElement(); + + return quat; + } + } + + public class PrimObject + { + public class FlexibleBlock + { + public int Softness; + public float Gravity; + public float Drag; + public float Wind; + public float Tension; + public Vector3 Force; + + public OSDMap Serialize() + { + OSDMap map = new OSDMap(); + map["softness"] = OSD.FromInteger(Softness); + map["gravity"] = OSD.FromReal(Gravity); + map["drag"] = OSD.FromReal(Drag); + map["wind"] = OSD.FromReal(Wind); + map["tension"] = OSD.FromReal(Tension); + map["force"] = OSD.FromVector3(Force); + return map; + } + + public void Deserialize(OSDMap map) + { + Softness = map["softness"].AsInteger(); + Gravity = (float)map["gravity"].AsReal(); + Drag = (float)map["drag"].AsReal(); + Wind = (float)map["wind"].AsReal(); + Tension = (float)map["tension"].AsReal(); + Force = map["force"].AsVector3(); + } + } + + public class LightBlock + { + public Color4 Color; + public float Intensity; + public float Radius; + public float Falloff; + public float Cutoff; + + public OSDMap Serialize() + { + OSDMap map = new OSDMap(); + map["color"] = OSD.FromColor4(Color); + map["intensity"] = OSD.FromReal(Intensity); + map["radius"] = OSD.FromReal(Radius); + map["falloff"] = OSD.FromReal(Falloff); + map["cutoff"] = OSD.FromReal(Cutoff); + return map; + } + + public void Deserialize(OSDMap map) + { + Color = map["color"].AsColor4(); + Intensity = (float)map["intensity"].AsReal(); + Radius = (float)map["radius"].AsReal(); + Falloff = (float)map["falloff"].AsReal(); + Cutoff = (float)map["cutoff"].AsReal(); + } + } + + public class SculptBlock + { + public UUID Texture; + public int Type; + + public OSDMap Serialize() + { + OSDMap map = new OSDMap(); + map["texture"] = OSD.FromUUID(Texture); + map["type"] = OSD.FromInteger(Type); + return map; + } + + public void Deserialize(OSDMap map) + { + Texture = map["texture"].AsUUID(); + Type = map["type"].AsInteger(); + } + } + + public class ParticlesBlock + { + public int Flags; + public int Pattern; + public float MaxAge; + public float StartAge; + public float InnerAngle; + public float OuterAngle; + public float BurstRate; + public float BurstRadius; + public float BurstSpeedMin; + public float BurstSpeedMax; + public int BurstParticleCount; + public Vector3 AngularVelocity; + public Vector3 Acceleration; + public UUID TextureID; + public UUID TargetID; + public int DataFlags; + public float ParticleMaxAge; + public Color4 ParticleStartColor; + public Color4 ParticleEndColor; + public Vector2 ParticleStartScale; + public Vector2 ParticleEndScale; + + public OSDMap Serialize() + { + OSDMap map = new OSDMap(); + map["flags"] = OSD.FromInteger(Flags); + map["pattern"] = OSD.FromInteger(Pattern); + map["max_age"] = OSD.FromReal(MaxAge); + map["start_age"] = OSD.FromReal(StartAge); + map["inner_angle"] = OSD.FromReal(InnerAngle); + map["outer_angle"] = OSD.FromReal(OuterAngle); + map["burst_rate"] = OSD.FromReal(BurstRate); + map["burst_radius"] = OSD.FromReal(BurstRadius); + map["burst_speed_min"] = OSD.FromReal(BurstSpeedMin); + map["burst_speed_max"] = OSD.FromReal(BurstSpeedMax); + map["burst_particle_count"] = OSD.FromInteger(BurstParticleCount); + map["angular_velocity"] = OSD.FromVector3(AngularVelocity); + map["acceleration"] = OSD.FromVector3(Acceleration); + map["texture_id"] = OSD.FromUUID(TextureID); + map["target_id"] = OSD.FromUUID(TargetID); + map["data_flags"] = OSD.FromInteger(DataFlags); + map["particle_max_age"] = OSD.FromReal(ParticleMaxAge); + map["particle_start_color"] = OSD.FromColor4(ParticleStartColor); + map["particle_end_color"] = OSD.FromColor4(ParticleEndColor); + map["particle_start_scale"] = OSD.FromVector2(ParticleStartScale); + map["particle_end_scale"] = OSD.FromVector2(ParticleEndScale); + return map; + } + + public void Deserialize(OSDMap map) + { + Flags = map["flags"].AsInteger(); + Pattern = map["pattern"].AsInteger(); + MaxAge = (float)map["max_age"].AsReal(); + StartAge = (float)map["start_age"].AsReal(); + InnerAngle = (float)map["inner_angle"].AsReal(); + OuterAngle = (float)map["outer_angle"].AsReal(); + BurstRate = (float)map["burst_rate"].AsReal(); + BurstRadius = (float)map["burst_radius"].AsReal(); + BurstSpeedMin = (float)map["burst_speed_min"].AsReal(); + BurstSpeedMax = (float)map["burst_speed_max"].AsReal(); + BurstParticleCount = map["burst_particle_count"].AsInteger(); + AngularVelocity = map["angular_velocity"].AsVector3(); + Acceleration = map["acceleration"].AsVector3(); + TextureID = map["texture_id"].AsUUID(); + DataFlags = map["data_flags"].AsInteger(); + ParticleMaxAge = (float)map["particle_max_age"].AsReal(); + ParticleStartColor = map["particle_start_color"].AsColor4(); + ParticleEndColor = map["particle_end_color"].AsColor4(); + ParticleStartScale = map["particle_start_scale"].AsVector2(); + ParticleEndScale = map["particle_end_scale"].AsVector2(); + } + } + + public class ShapeBlock + { + public int PathCurve; + public float PathBegin; + public float PathEnd; + public float PathScaleX; + public float PathScaleY; + public float PathShearX; + public float PathShearY; + public float PathTwist; + public float PathTwistBegin; + public float PathRadiusOffset; + public float PathTaperX; + public float PathTaperY; + public float PathRevolutions; + public float PathSkew; + public int ProfileCurve; + public float ProfileBegin; + public float ProfileEnd; + public float ProfileHollow; + + public OSDMap Serialize() + { + OSDMap map = new OSDMap(); + map["path_curve"] = OSD.FromInteger(PathCurve); + map["path_begin"] = OSD.FromReal(PathBegin); + map["path_end"] = OSD.FromReal(PathEnd); + map["path_scale_x"] = OSD.FromReal(PathScaleX); + map["path_scale_y"] = OSD.FromReal(PathScaleY); + map["path_shear_x"] = OSD.FromReal(PathShearX); + map["path_shear_y"] = OSD.FromReal(PathShearY); + map["path_twist"] = OSD.FromReal(PathTwist); + map["path_twist_begin"] = OSD.FromReal(PathTwistBegin); + map["path_radius_offset"] = OSD.FromReal(PathRadiusOffset); + map["path_taper_x"] = OSD.FromReal(PathTaperX); + map["path_taper_y"] = OSD.FromReal(PathTaperY); + map["path_revolutions"] = OSD.FromReal(PathRevolutions); + map["path_skew"] = OSD.FromReal(PathSkew); + map["profile_curve"] = OSD.FromInteger(ProfileCurve); + map["profile_begin"] = OSD.FromReal(ProfileBegin); + map["profile_end"] = OSD.FromReal(ProfileEnd); + map["profile_hollow"] = OSD.FromReal(ProfileHollow); + return map; + } + + public void Deserialize(OSDMap map) + { + PathCurve = map["path_curve"].AsInteger(); + PathBegin = (float)map["path_begin"].AsReal(); + PathEnd = (float)map["path_end"].AsReal(); + PathScaleX = (float)map["path_scale_x"].AsReal(); + PathScaleY = (float)map["path_scale_y"].AsReal(); + PathShearX = (float)map["path_shear_x"].AsReal(); + PathShearY = (float)map["path_shear_y"].AsReal(); + PathTwist = (float)map["path_twist"].AsReal(); + PathTwistBegin = (float)map["path_twist_begin"].AsReal(); + PathRadiusOffset = (float)map["path_radius_offset"].AsReal(); + PathTaperX = (float)map["path_taper_x"].AsReal(); + PathTaperY = (float)map["path_taper_y"].AsReal(); + PathRevolutions = (float)map["path_revolutions"].AsReal(); + PathSkew = (float)map["path_skew"].AsReal(); + ProfileCurve = map["profile_curve"].AsInteger(); + ProfileBegin = (float)map["profile_begin"].AsReal(); + ProfileEnd = (float)map["profile_end"].AsReal(); + ProfileHollow = (float)map["profile_hollow"].AsReal(); + } + } + + public class FaceBlock + { + public int FaceIndex; + public UUID ImageID; + public Color4 Color; + public float ScaleS; + public float ScaleT; + public float OffsetS; + public float OffsetT; + public float ImageRot; + public int Bump; + public bool FullBright; + public int MediaFlags; + + public OSDMap Serialize() + { + OSDMap map = new OSDMap(); + map["face_index"] = OSD.FromInteger(FaceIndex); + map["image_id"] = OSD.FromUUID(ImageID); + map["color"] = OSD.FromColor4(Color); + map["scale_s"] = OSD.FromReal(ScaleS); + map["scale_t"] = OSD.FromReal(ScaleT); + map["offset_s"] = OSD.FromReal(OffsetS); + map["offset_t"] = OSD.FromReal(OffsetT); + map["image_rot"] = OSD.FromReal(ImageRot); + map["bump"] = OSD.FromInteger(Bump); + map["full_bright"] = OSD.FromBoolean(FullBright); + map["media_flags"] = OSD.FromInteger(MediaFlags); + return map; + } + + public void Deserialize(OSDMap map) + { + FaceIndex = map["face_index"].AsInteger(); + ImageID = map["image_id"].AsUUID(); + Color = map["color"].AsColor4(); + ScaleS = (float)map["scale_s"].AsReal(); + ScaleT = (float)map["scale_t"].AsReal(); + OffsetS = (float)map["offset_s"].AsReal(); + OffsetT = (float)map["offset_t"].AsReal(); + ImageRot = (float)map["image_rot"].AsReal(); + Bump = map["bump"].AsInteger(); + FullBright = map["full_bright"].AsBoolean(); + MediaFlags = map["media_flags"].AsInteger(); + } + } + + public class InventoryBlock + { + public class ItemBlock + { + public UUID ID; + public string Name; + public string OwnerIdentity; + public string CreatorIdentity; + public string GroupIdentity; + public UUID AssetID; + public string ContentType; + public string Description; + public uint PermsBase; + public uint PermsOwner; + public uint PermsGroup; + public uint PermsEveryone; + public uint PermsNextOwner; + public int SalePrice; + public int SaleType; + public int Flags; + public DateTime CreationDate; + + public OSDMap Serialize() + { + OSDMap map = new OSDMap(); + map["id"] = OSD.FromUUID(ID); + map["name"] = OSD.FromString(Name); + map["owner_identity"] = OSD.FromString(OwnerIdentity); + map["creator_identity"] = OSD.FromString(CreatorIdentity); + map["group_identity"] = OSD.FromString(GroupIdentity); + map["asset_id"] = OSD.FromUUID(AssetID); + map["content_type"] = OSD.FromString(ContentType); + map["description"] = OSD.FromString(Description); + map["perms_base"] = OSD.FromInteger(PermsBase); + map["perms_owner"] = OSD.FromInteger(PermsOwner); + map["perms_group"] = OSD.FromInteger(PermsGroup); + map["perms_everyone"] = OSD.FromInteger(PermsEveryone); + map["perms_next_owner"] = OSD.FromInteger(PermsNextOwner); + map["sale_price"] = OSD.FromInteger(SalePrice); + map["sale_type"] = OSD.FromInteger(SaleType); + map["flags"] = OSD.FromInteger(Flags); + map["creation_date"] = OSD.FromDate(CreationDate); + return map; + } + + public void Deserialize(OSDMap map) + { + ID = map["id"].AsUUID(); + Name = map["name"].AsString(); + OwnerIdentity = map["owner_identity"].AsString(); + CreatorIdentity = map["creator_identity"].AsString(); + GroupIdentity = map["group_identity"].AsString(); + AssetID = map["asset_id"].AsUUID(); + ContentType = map["content_type"].AsString(); + Description = map["description"].AsString(); + PermsBase = (uint)map["perms_base"].AsInteger(); + PermsOwner = (uint)map["perms_owner"].AsInteger(); + PermsGroup = (uint)map["perms_group"].AsInteger(); + PermsEveryone = (uint)map["perms_everyone"].AsInteger(); + PermsNextOwner = (uint)map["perms_next_owner"].AsInteger(); + SalePrice = map["sale_price"].AsInteger(); + SaleType = map["sale_type"].AsInteger(); + Flags = map["flags"].AsInteger(); + CreationDate = map["creation_date"].AsDate(); + } + } + + public int Serial; + public ItemBlock[] Items; + + public OSDMap Serialize() + { + OSDMap map = new OSDMap(); + map["serial"] = OSD.FromInteger(Serial); + + if (Items != null) + { + OSDArray array = new OSDArray(Items.Length); + for (int i = 0; i < Items.Length; i++) + array.Add(Items[i].Serialize()); + map["items"] = array; + } + + return map; + } + + public void Deserialize(OSDMap map) + { + Serial = map["serial"].AsInteger(); + + if (map.ContainsKey("items")) + { + OSDArray array = (OSDArray)map["items"]; + Items = new ItemBlock[array.Count]; + + for (int i = 0; i < array.Count; i++) + { + ItemBlock item = new ItemBlock(); + item.Deserialize((OSDMap)array[i]); + Items[i] = item; + } + } + else + { + Items = new ItemBlock[0]; + } + } + } + + public UUID ID; + public Vector3 AttachmentPosition; + public Quaternion AttachmentRotation; + public Quaternion BeforeAttachmentRotation; + public string Name; + public string Description; + public uint PermsBase; + public uint PermsOwner; + public uint PermsGroup; + public uint PermsEveryone; + public uint PermsNextOwner; + public string CreatorIdentity; + public string OwnerIdentity; + public string LastOwnerIdentity; + public string GroupIdentity; + public UUID FolderID; + public ulong RegionHandle; + public int ClickAction; + public int LastAttachmentPoint; + public int LinkNumber; + public uint LocalID; + public uint ParentID; + public Vector3 Position; + public Quaternion Rotation; + public Vector3 Velocity; + public Vector3 AngularVelocity; + public Vector3 Acceleration; + public Vector3 Scale; + public Vector3 SitOffset; + public Quaternion SitRotation; + public Vector3 CameraEyeOffset; + public Vector3 CameraAtOffset; + public int State; + public int PCode; + public int Material; + public UUID SoundID; + public float SoundGain; + public float SoundRadius; + public int SoundFlags; + public Color4 TextColor; + public string Text; + public string SitName; + public string TouchName; + public bool Selected; + public UUID SelectorID; + public bool UsePhysics; + public bool Phantom; + public int RemoteScriptAccessPIN; + public bool VolumeDetect; + public bool DieAtEdge; + public bool ReturnAtEdge; + public bool Temporary; + public bool Sandbox; + public DateTime CreationDate; + public DateTime RezDate; + public int SalePrice; + public int SaleType; + public byte[] ScriptState; + public FlexibleBlock Flexible; + public LightBlock Light; + public SculptBlock Sculpt; + public ParticlesBlock Particles; + public ShapeBlock Shape; + public FaceBlock[] Faces; + public InventoryBlock Inventory; + + public OSDMap Serialize() + { + OSDMap map = new OSDMap(); + map["id"] = OSD.FromUUID(ID); + map["attachment_position"] = OSD.FromVector3(AttachmentPosition); + map["attachment_rotation"] = OSD.FromQuaternion(AttachmentRotation); + map["before_attachment_rotation"] = OSD.FromQuaternion(BeforeAttachmentRotation); + map["name"] = OSD.FromString(Name); + map["description"] = OSD.FromString(Description); + map["perms_base"] = OSD.FromInteger(PermsBase); + map["perms_owner"] = OSD.FromInteger(PermsOwner); + map["perms_group"] = OSD.FromInteger(PermsGroup); + map["perms_everyone"] = OSD.FromInteger(PermsEveryone); + map["perms_next_owner"] = OSD.FromInteger(PermsNextOwner); + map["creator_identity"] = OSD.FromString(CreatorIdentity); + map["owner_identity"] = OSD.FromString(OwnerIdentity); + map["last_owner_identity"] = OSD.FromString(LastOwnerIdentity); + map["group_identity"] = OSD.FromString(GroupIdentity); + map["folder_id"] = OSD.FromUUID(FolderID); + map["region_handle"] = OSD.FromULong(RegionHandle); + map["click_action"] = OSD.FromInteger(ClickAction); + map["last_attachment_point"] = OSD.FromInteger(LastAttachmentPoint); + map["link_number"] = OSD.FromInteger(LinkNumber); + map["local_id"] = OSD.FromInteger(LocalID); + map["parent_id"] = OSD.FromInteger(ParentID); + map["position"] = OSD.FromVector3(Position); + map["rotation"] = OSD.FromQuaternion(Rotation); + map["velocity"] = OSD.FromVector3(Velocity); + map["angular_velocity"] = OSD.FromVector3(AngularVelocity); + map["acceleration"] = OSD.FromVector3(Acceleration); + map["scale"] = OSD.FromVector3(Scale); + map["sit_offset"] = OSD.FromVector3(SitOffset); + map["sit_rotation"] = OSD.FromQuaternion(SitRotation); + map["camera_eye_offset"] = OSD.FromVector3(CameraEyeOffset); + map["camera_at_offset"] = OSD.FromVector3(CameraAtOffset); + map["state"] = OSD.FromInteger(State); + map["prim_code"] = OSD.FromInteger(PCode); + map["material"] = OSD.FromInteger(Material); + map["sound_id"] = OSD.FromUUID(SoundID); + map["sound_gain"] = OSD.FromReal(SoundGain); + map["sound_radius"] = OSD.FromReal(SoundRadius); + map["sound_flags"] = OSD.FromInteger(SoundFlags); + map["text_color"] = OSD.FromColor4(TextColor); + map["text"] = OSD.FromString(Text); + map["sit_name"] = OSD.FromString(SitName); + map["touch_name"] = OSD.FromString(TouchName); + map["selected"] = OSD.FromBoolean(Selected); + map["selector_id"] = OSD.FromUUID(SelectorID); + map["use_physics"] = OSD.FromBoolean(UsePhysics); + map["phantom"] = OSD.FromBoolean(Phantom); + map["remote_script_access_pin"] = OSD.FromInteger(RemoteScriptAccessPIN); + map["volume_detect"] = OSD.FromBoolean(VolumeDetect); + map["die_at_edge"] = OSD.FromBoolean(DieAtEdge); + map["return_at_edge"] = OSD.FromBoolean(ReturnAtEdge); + map["temporary"] = OSD.FromBoolean(Temporary); + map["sandbox"] = OSD.FromBoolean(Sandbox); + map["creation_date"] = OSD.FromDate(CreationDate); + map["rez_date"] = OSD.FromDate(RezDate); + map["sale_price"] = OSD.FromInteger(SalePrice); + map["sale_type"] = OSD.FromInteger(SaleType); + + if (Flexible != null) + map["flexible"] = Flexible.Serialize(); + if (Light != null) + map["light"] = Light.Serialize(); + if (Sculpt != null) + map["sculpt"] = Sculpt.Serialize(); + if (Particles != null) + map["particles"] = Particles.Serialize(); + if (Shape != null) + map["shape"] = Shape.Serialize(); + if (Faces != null) + { + OSDArray array = new OSDArray(Faces.Length); + for (int i = 0; i < Faces.Length; i++) + array.Add(Faces[i].Serialize()); + map["faces"] = array; + } + if (Inventory != null) + map["inventory"] = Inventory.Serialize(); + + return map; + } + + public void Deserialize(OSDMap map) + { + ID = map["id"].AsUUID(); + AttachmentPosition = map["attachment_position"].AsVector3(); + AttachmentRotation = map["attachment_rotation"].AsQuaternion(); + BeforeAttachmentRotation = map["before_attachment_rotation"].AsQuaternion(); + Name = map["name"].AsString(); + Description = map["description"].AsString(); + PermsBase = (uint)map["perms_base"].AsInteger(); + PermsOwner = (uint)map["perms_owner"].AsInteger(); + PermsGroup = (uint)map["perms_group"].AsInteger(); + PermsEveryone = (uint)map["perms_everyone"].AsInteger(); + PermsNextOwner = (uint)map["perms_next_owner"].AsInteger(); + CreatorIdentity = map["creator_identity"].AsString(); + OwnerIdentity = map["owner_identity"].AsString(); + LastOwnerIdentity = map["last_owner_identity"].AsString(); + GroupIdentity = map["group_identity"].AsString(); + FolderID = map["folder_id"].AsUUID(); + RegionHandle = map["region_handle"].AsULong(); + ClickAction = map["click_action"].AsInteger(); + LastAttachmentPoint = map["last_attachment_point"].AsInteger(); + LinkNumber = map["link_number"].AsInteger(); + LocalID = (uint)map["local_id"].AsInteger(); + ParentID = (uint)map["parent_id"].AsInteger(); + Position = map["position"].AsVector3(); + Rotation = map["rotation"].AsQuaternion(); + Velocity = map["velocity"].AsVector3(); + AngularVelocity = map["angular_velocity"].AsVector3(); + Acceleration = map["acceleration"].AsVector3(); + Scale = map["scale"].AsVector3(); + SitOffset = map["sit_offset"].AsVector3(); + SitRotation = map["sit_rotation"].AsQuaternion(); + CameraEyeOffset = map["camera_eye_offset"].AsVector3(); + CameraAtOffset = map["camera_at_offset"].AsVector3(); + State = map["state"].AsInteger(); + PCode = map["prim_code"].AsInteger(); + Material = map["material"].AsInteger(); + SoundID = map["sound_id"].AsUUID(); + SoundGain = (float)map["sound_gain"].AsReal(); + SoundRadius = (float)map["sound_radius"].AsReal(); + SoundFlags = map["sound_flags"].AsInteger(); + TextColor = map["text_color"].AsColor4(); + Text = map["text"].AsString(); + SitName = map["sit_name"].AsString(); + TouchName = map["touch_name"].AsString(); + Selected = map["selected"].AsBoolean(); + SelectorID = map["selector_id"].AsUUID(); + UsePhysics = map["use_physics"].AsBoolean(); + Phantom = map["phantom"].AsBoolean(); + RemoteScriptAccessPIN = map["remote_script_access_pin"].AsInteger(); + VolumeDetect = map["volume_detect"].AsBoolean(); + DieAtEdge = map["die_at_edge"].AsBoolean(); + ReturnAtEdge = map["return_at_edge"].AsBoolean(); + Temporary = map["temporary"].AsBoolean(); + Sandbox = map["sandbox"].AsBoolean(); + CreationDate = map["creation_date"].AsDate(); + RezDate = map["rez_date"].AsDate(); + SalePrice = map["sale_price"].AsInteger(); + SaleType = map["sale_type"].AsInteger(); + } + } +} diff --git a/OpenMetaverse/Assets/AssetTypes/AssetScriptBinary.cs b/OpenMetaverse/Assets/AssetTypes/AssetScriptBinary.cs new file mode 100644 index 00000000..5f080b11 --- /dev/null +++ b/OpenMetaverse/Assets/AssetTypes/AssetScriptBinary.cs @@ -0,0 +1,64 @@ +/* + * Copyright (c) 2009, openmetaverse.org + * All rights reserved. + * + * - 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. + * - Neither the name of the openmetaverse.org 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 COPYRIGHT HOLDERS AND CONTRIBUTORS "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 COPYRIGHT OWNER OR 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 System; +using OpenMetaverse; + +namespace OpenMetaverse.Assets +{ + /// + /// Represents an AssetScriptBinary object containing the + /// LSO compiled bytecode of an LSL script + /// + public class AssetScriptBinary : Asset + { + /// Override the base classes AssetType + public override AssetType AssetType { get { return AssetType.LSLBytecode; } } + + /// Initializes a new instance of an AssetScriptBinary object + public AssetScriptBinary() { } + + /// Initializes a new instance of an AssetScriptBinary object with parameters + /// A unique specific to this asset + /// A byte array containing the raw asset data + public AssetScriptBinary(UUID assetID, byte[] assetData) + : base(assetID, assetData) + { + AssetData = assetData; + } + + /// + /// TODO: Encodes a scripts contents into a LSO Bytecode file + /// + public override void Encode() { } + + /// + /// TODO: Decode LSO Bytecode into a string + /// + /// true + public override bool Decode() { return true; } + } +} diff --git a/OpenMetaverse/Assets/AssetTypes/AssetScriptText.cs b/OpenMetaverse/Assets/AssetTypes/AssetScriptText.cs new file mode 100644 index 00000000..08ab9a0c --- /dev/null +++ b/OpenMetaverse/Assets/AssetTypes/AssetScriptText.cs @@ -0,0 +1,80 @@ +/* + * Copyright (c) 2009, openmetaverse.org + * All rights reserved. + * + * - 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. + * - Neither the name of the openmetaverse.org 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 COPYRIGHT HOLDERS AND CONTRIBUTORS "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 COPYRIGHT OWNER OR 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 System; +using OpenMetaverse; + +namespace OpenMetaverse.Assets +{ + /// + /// Represents an LSL Text object containing a string of UTF encoded characters + /// + public class AssetScriptText : Asset + { + /// Override the base classes AssetType + public override AssetType AssetType { get { return AssetType.LSLText; } } + + /// A string of characters represting the script contents + public string Source; + + /// Initializes a new AssetScriptText object + public AssetScriptText() { } + + /// + /// Initializes a new AssetScriptText object with parameters + /// + /// A unique specific to this asset + /// A byte array containing the raw asset data + public AssetScriptText(UUID assetID, byte[] assetData) : base(assetID, assetData) { } + + /// + /// Initializes a new AssetScriptText object with parameters + /// + /// A string containing the scripts contents + public AssetScriptText(string source) + { + Source = source; + } + + /// + /// Encode a string containing the scripts contents into byte encoded AssetData + /// + public override void Encode() + { + AssetData = Utils.StringToBytes(Source); + } + + /// + /// Decode a byte array containing the scripts contents into a string + /// + /// true if decoding is successful + public override bool Decode() + { + Source = Utils.BytesToString(AssetData); + return true; + } + } +} diff --git a/OpenMetaverse/Assets/AssetTypes/AssetSound.cs b/OpenMetaverse/Assets/AssetTypes/AssetSound.cs new file mode 100644 index 00000000..50a4b42e --- /dev/null +++ b/OpenMetaverse/Assets/AssetTypes/AssetSound.cs @@ -0,0 +1,63 @@ +/* + * Copyright (c) 2009, openmetaverse.org + * All rights reserved. + * + * - 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. + * - Neither the name of the openmetaverse.org 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 COPYRIGHT HOLDERS AND CONTRIBUTORS "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 COPYRIGHT OWNER OR 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 System; +using OpenMetaverse; + +namespace OpenMetaverse.Assets +{ + /// + /// Represents a Sound Asset + /// + public class AssetSound : Asset + { + /// Override the base classes AssetType + public override AssetType AssetType { get { return AssetType.Sound; } } + + /// Initializes a new instance of an AssetSound object + public AssetSound() { } + + /// Initializes a new instance of an AssetSound object with parameters + /// A unique specific to this asset + /// A byte array containing the raw asset data + public AssetSound(UUID assetID, byte[] assetData) + : base(assetID, assetData) + { + AssetData = assetData; + } + + /// + /// TODO: Encodes a sound file + /// + public override void Encode() { } + + /// + /// TODO: Decode a sound file + /// + /// true + public override bool Decode() { return true; } + } +} diff --git a/OpenMetaverse/Assets/AssetTypes/AssetTexture.cs b/OpenMetaverse/Assets/AssetTypes/AssetTexture.cs new file mode 100644 index 00000000..2ece85f6 --- /dev/null +++ b/OpenMetaverse/Assets/AssetTypes/AssetTexture.cs @@ -0,0 +1,125 @@ +/* + * Copyright (c) 2009, openmetaverse.org + * All rights reserved. + * + * - 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. + * - Neither the name of the openmetaverse.org 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 COPYRIGHT HOLDERS AND CONTRIBUTORS "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 COPYRIGHT OWNER OR 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 System; +using OpenMetaverse; +using OpenMetaverse.Imaging; + +namespace OpenMetaverse.Assets +{ + /// + /// Represents a texture + /// + public class AssetTexture : Asset + { + /// Override the base classes AssetType + public override AssetType AssetType { get { return AssetType.Texture; } } + + /// A object containing image data + public ManagedImage Image; + + /// + public OpenJPEG.J2KLayerInfo[] LayerInfo; + + /// + public int Components; + + /// Initializes a new instance of an AssetTexture object + public AssetTexture() { } + + /// + /// Initializes a new instance of an AssetTexture object + /// + /// A unique specific to this asset + /// A byte array containing the raw asset data + public AssetTexture(UUID assetID, byte[] assetData) : base(assetID, assetData) { } + + /// + /// Initializes a new instance of an AssetTexture object + /// + /// A object containing texture data + public AssetTexture(ManagedImage image) + { + Image = image; + Components = 0; + if ((Image.Channels & ManagedImage.ImageChannels.Color) != 0) + Components += 3; + if ((Image.Channels & ManagedImage.ImageChannels.Gray) != 0) + ++Components; + if ((Image.Channels & ManagedImage.ImageChannels.Bump) != 0) + ++Components; + if ((Image.Channels & ManagedImage.ImageChannels.Alpha) != 0) + ++Components; + } + + /// + /// Populates the byte array with a JPEG2000 + /// encoded image created from the data in + /// + public override void Encode() + { + AssetData = OpenJPEG.Encode(Image); + } + + /// + /// Decodes the JPEG2000 data in AssetData to the + /// object + /// + /// True if the decoding was successful, otherwise false + public override bool Decode() + { + Components = 0; + + if (OpenJPEG.DecodeToImage(AssetData, out Image)) + { + if ((Image.Channels & ManagedImage.ImageChannels.Color) != 0) + Components += 3; + if ((Image.Channels & ManagedImage.ImageChannels.Gray) != 0) + ++Components; + if ((Image.Channels & ManagedImage.ImageChannels.Bump) != 0) + ++Components; + if ((Image.Channels & ManagedImage.ImageChannels.Alpha) != 0) + ++Components; + + return true; + } + else + { + return false; + } + } + + /// + /// Decodes the begin and end byte positions for each quality layer in + /// the image + /// + /// + public bool DecodeLayerBoundaries() + { + return OpenJPEG.DecodeLayerBoundaries(AssetData, out LayerInfo, out Components); + } + } +} diff --git a/OpenMetaverse/Assets/AssetTypes/AssetWearable.cs b/OpenMetaverse/Assets/AssetTypes/AssetWearable.cs new file mode 100644 index 00000000..0adb20fc --- /dev/null +++ b/OpenMetaverse/Assets/AssetTypes/AssetWearable.cs @@ -0,0 +1,260 @@ +/* + * Copyright (c) 2009, openmetaverse.org + * All rights reserved. + * + * - 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. + * - Neither the name of the openmetaverse.org 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 COPYRIGHT HOLDERS AND CONTRIBUTORS "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 COPYRIGHT OWNER OR 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 System; +using System.Collections.Generic; +using System.Text; +using OpenMetaverse; + +namespace OpenMetaverse.Assets +{ + /// + /// Represents a Wearable Asset, Clothing, Hair, Skin, Etc + /// + public abstract class AssetWearable : Asset + { + /// A string containing the name of the asset + public string Name = String.Empty; + /// A string containing a short description of the asset + public string Description = String.Empty; + /// The Assets WearableType + public WearableType WearableType = WearableType.Shape; + /// The For-Sale status of the object + public SaleType ForSale; + /// An Integer representing the purchase price of the asset + public int SalePrice; + /// The of the assets creator + public UUID Creator; + /// The of the assets current owner + public UUID Owner; + /// The of the assets prior owner + public UUID LastOwner; + /// The of the Group this asset is set to + public UUID Group; + /// True if the asset is owned by a + public bool GroupOwned; + /// The Permissions mask of the asset + public Permissions Permissions; + /// A Dictionary containing Key/Value pairs of the objects parameters + public Dictionary Params = new Dictionary(); + /// A Dictionary containing Key/Value pairs where the Key is the textures Index and the Value is the Textures + public Dictionary Textures = new Dictionary(); + + /// Initializes a new instance of an AssetWearable object + public AssetWearable() { } + + /// Initializes a new instance of an AssetWearable object with parameters + /// A unique specific to this asset + /// A byte array containing the raw asset data + public AssetWearable(UUID assetID, byte[] assetData) : base(assetID, assetData) { } + + /// Initializes a new instance of an AssetWearable object with parameters + /// A string containing the asset parameters + public AssetWearable(string source) + { + AssetData = Utils.StringToBytes(source); + } + + /// + /// Decode an assets byte encoded data to a string + /// + /// true if the asset data was decoded successfully + public override bool Decode() + { + int version = -1; + Permissions = new Permissions(); + string data = Utils.BytesToString(AssetData); + + data = data.Replace("\r", String.Empty); + string[] lines = data.Split('\n'); + for (int stri = 0; stri < lines.Length; stri++) + { + if (stri == 0) + { + string versionstring = lines[stri]; + version = Int32.Parse(versionstring.Split(' ')[2]); + if (version != 22 && version != 18) + return false; + } + else if (stri == 1) + { + Name = lines[stri]; + } + else if (stri == 2) + { + Description = lines[stri]; + } + else + { + string line = lines[stri].Trim(); + string[] fields = line.Split('\t'); + + if (fields.Length == 1) + { + fields = line.Split(' '); + if (fields[0] == "parameters") + { + int count = Int32.Parse(fields[1]) + stri; + for (; stri < count; ) + { + stri++; + line = lines[stri].Trim(); + fields = line.Split(' '); + + int id = Int32.Parse(fields[0]); + if (fields[1] == ",") + fields[1] = "0"; + else + fields[1] = fields[1].Replace(',', '.'); + + float weight = float.Parse(fields[1], System.Globalization.NumberStyles.Float, + Utils.EnUsCulture.NumberFormat); + + Params[id] = weight; + } + } + else if (fields[0] == "textures") + { + int count = Int32.Parse(fields[1]) + stri; + for (; stri < count; ) + { + stri++; + line = lines[stri].Trim(); + fields = line.Split(' '); + + AppearanceManager.TextureIndex id = (AppearanceManager.TextureIndex)Int32.Parse(fields[0]); + UUID texture = new UUID(fields[1]); + + Textures[id] = texture; + } + } + else if (fields[0] == "type") + { + WearableType = (WearableType)Int32.Parse(fields[1]); + } + + } + else if (fields.Length == 2) + { + switch (fields[0]) + { + case "creator_mask": + // Deprecated, apply this as the base mask + Permissions.BaseMask = (PermissionMask)UInt32.Parse(fields[1], System.Globalization.NumberStyles.HexNumber); + break; + case "base_mask": + Permissions.BaseMask = (PermissionMask)UInt32.Parse(fields[1], System.Globalization.NumberStyles.HexNumber); + break; + case "owner_mask": + Permissions.OwnerMask = (PermissionMask)UInt32.Parse(fields[1], System.Globalization.NumberStyles.HexNumber); + break; + case "group_mask": + Permissions.GroupMask = (PermissionMask)UInt32.Parse(fields[1], System.Globalization.NumberStyles.HexNumber); + break; + case "everyone_mask": + Permissions.EveryoneMask = (PermissionMask)UInt32.Parse(fields[1], System.Globalization.NumberStyles.HexNumber); + break; + case "next_owner_mask": + Permissions.NextOwnerMask = (PermissionMask)UInt32.Parse(fields[1], System.Globalization.NumberStyles.HexNumber); + break; + case "creator_id": + Creator = new UUID(fields[1]); + break; + case "owner_id": + Owner = new UUID(fields[1]); + break; + case "last_owner_id": + LastOwner = new UUID(fields[1]); + break; + case "group_id": + Group = new UUID(fields[1]); + break; + case "group_owned": + GroupOwned = (Int32.Parse(fields[1]) != 0); + break; + case "sale_type": + ForSale = Utils.StringToSaleType(fields[1]); + break; + case "sale_price": + SalePrice = Int32.Parse(fields[1]); + break; + case "sale_info": + // Container for sale_type and sale_price, ignore + break; + default: + return false; + } + } + } + } + + return true; + } + + /// + /// Encode the assets string represantion into a format consumable by the asset server + /// + public override void Encode() + { + const string NL = "\n"; + + StringBuilder data = new StringBuilder("LLWearable version 22\n"); + data.Append(Name); data.Append(NL); data.Append(NL); + data.Append("\tpermissions 0\n\t{\n"); + data.Append("\t\tbase_mask\t"); data.Append(Utils.UIntToHexString((uint)Permissions.BaseMask)); data.Append(NL); + data.Append("\t\towner_mask\t"); data.Append(Utils.UIntToHexString((uint)Permissions.OwnerMask)); data.Append(NL); + data.Append("\t\tgroup_mask\t"); data.Append(Utils.UIntToHexString((uint)Permissions.GroupMask)); data.Append(NL); + data.Append("\t\teveryone_mask\t"); data.Append(Utils.UIntToHexString((uint)Permissions.EveryoneMask)); data.Append(NL); + data.Append("\t\tnext_owner_mask\t"); data.Append(Utils.UIntToHexString((uint)Permissions.NextOwnerMask)); data.Append(NL); + data.Append("\t\tcreator_id\t"); data.Append(Creator.ToString()); data.Append(NL); + data.Append("\t\towner_id\t"); data.Append(Owner.ToString()); data.Append(NL); + data.Append("\t\tlast_owner_id\t"); data.Append(LastOwner.ToString()); data.Append(NL); + data.Append("\t\tgroup_id\t"); data.Append(Group.ToString()); data.Append(NL); + if (GroupOwned) data.Append("\t\tgroup_owned\t1\n"); + data.Append("\t}\n"); + data.Append("\tsale_info\t0\n"); + data.Append("\t{\n"); + data.Append("\t\tsale_type\t"); data.Append(Utils.SaleTypeToString(ForSale)); data.Append(NL); + data.Append("\t\tsale_price\t"); data.Append(SalePrice); data.Append(NL); + data.Append("\t}\n"); + data.Append("type "); data.Append((int)WearableType); data.Append(NL); + + data.Append("parameters "); data.Append(Params.Count); data.Append(NL); + foreach (KeyValuePair param in Params) + { + data.Append(param.Key); data.Append(" "); data.Append(Helpers.FloatToTerseString(param.Value)); data.Append(NL); + } + + data.Append("textures "); data.Append(Textures.Count); data.Append(NL); + foreach (KeyValuePair texture in Textures) + { + data.Append((byte)texture.Key); data.Append(" "); data.Append(texture.Value.ToString()); data.Append(NL); + } + + AssetData = Utils.StringToBytes(data.ToString()); + } + } +} diff --git a/OpenMetaverse/Imaging/BakeLayer.cs b/OpenMetaverse/Imaging/BakeLayer.cs index f7fde542..f38b6dc3 100644 --- a/OpenMetaverse/Imaging/BakeLayer.cs +++ b/OpenMetaverse/Imaging/BakeLayer.cs @@ -30,7 +30,7 @@ using System.IO; using System.Reflection; using System.Drawing; using System.Drawing.Imaging; -//using OpenMetaverse.Assets; +using OpenMetaverse.Assets; namespace OpenMetaverse.Imaging { diff --git a/OpenMetaverse/TexturePipeline.cs b/OpenMetaverse/TexturePipeline.cs index 1d9a947e..9c9ca4af 100644 --- a/OpenMetaverse/TexturePipeline.cs +++ b/OpenMetaverse/TexturePipeline.cs @@ -30,6 +30,7 @@ using System; using System.Collections.Generic; using System.Threading; using OpenMetaverse.Packets; +using OpenMetaverse.Assets; namespace OpenMetaverse { diff --git a/Programs/AvatarPreview/frmAvatar.cs b/Programs/AvatarPreview/frmAvatar.cs index c11ce28b..6519c19a 100644 --- a/Programs/AvatarPreview/frmAvatar.cs +++ b/Programs/AvatarPreview/frmAvatar.cs @@ -14,6 +14,7 @@ using Tao.Platform.Windows; using OpenMetaverse; using OpenMetaverse.Imaging; using OpenMetaverse.Rendering; +using OpenMetaverse.Assets; namespace AvatarPreview { diff --git a/Programs/PrimWorkshop/frmBrowser.cs b/Programs/PrimWorkshop/frmBrowser.cs index 572813ee..83a98765 100644 --- a/Programs/PrimWorkshop/frmBrowser.cs +++ b/Programs/PrimWorkshop/frmBrowser.cs @@ -13,6 +13,7 @@ using OpenMetaverse; using OpenMetaverse.StructuredData; using OpenMetaverse.Imaging; using OpenMetaverse.Rendering; +using OpenMetaverse.Assets; namespace PrimWorkshop { diff --git a/Programs/examples/TestClient/Commands/Inventory/BackupCommand.cs b/Programs/examples/TestClient/Commands/Inventory/BackupCommand.cs index 44a6d900..03e51e54 100644 --- a/Programs/examples/TestClient/Commands/Inventory/BackupCommand.cs +++ b/Programs/examples/TestClient/Commands/Inventory/BackupCommand.cs @@ -9,6 +9,7 @@ using System.Xml.Serialization; using OpenMetaverse; using OpenMetaverse.Packets; using OpenMetaverse.TestClient; +using OpenMetaverse.Assets; namespace OpenMetaverse.TestClient { diff --git a/Programs/examples/TestClient/Commands/Inventory/DownloadCommand.cs b/Programs/examples/TestClient/Commands/Inventory/DownloadCommand.cs index 2fb82247..17d446e8 100644 --- a/Programs/examples/TestClient/Commands/Inventory/DownloadCommand.cs +++ b/Programs/examples/TestClient/Commands/Inventory/DownloadCommand.cs @@ -2,6 +2,7 @@ using System.IO; using System.Threading; using OpenMetaverse; +using OpenMetaverse.Assets; namespace OpenMetaverse.TestClient { diff --git a/Programs/examples/TestClient/Commands/Inventory/DumpOutfitCommand.cs b/Programs/examples/TestClient/Commands/Inventory/DumpOutfitCommand.cs index ee5a560f..acde1d1f 100644 --- a/Programs/examples/TestClient/Commands/Inventory/DumpOutfitCommand.cs +++ b/Programs/examples/TestClient/Commands/Inventory/DumpOutfitCommand.cs @@ -4,6 +4,7 @@ using System.IO; using System.Collections.Generic; using OpenMetaverse; using OpenMetaverse.Imaging; +using OpenMetaverse.Assets; namespace OpenMetaverse.TestClient { diff --git a/Programs/examples/TestClient/Commands/Inventory/ViewNotecardCommand.cs b/Programs/examples/TestClient/Commands/Inventory/ViewNotecardCommand.cs index ea824540..1a083139 100644 --- a/Programs/examples/TestClient/Commands/Inventory/ViewNotecardCommand.cs +++ b/Programs/examples/TestClient/Commands/Inventory/ViewNotecardCommand.cs @@ -2,6 +2,7 @@ using System; using System.Collections.Generic; using OpenMetaverse; using OpenMetaverse.Packets; +using OpenMetaverse.Assets; namespace OpenMetaverse.TestClient { diff --git a/Programs/examples/TestClient/Commands/Prims/DownloadTextureCommand.cs b/Programs/examples/TestClient/Commands/Prims/DownloadTextureCommand.cs index bc9b2437..1d55e451 100644 --- a/Programs/examples/TestClient/Commands/Prims/DownloadTextureCommand.cs +++ b/Programs/examples/TestClient/Commands/Prims/DownloadTextureCommand.cs @@ -2,6 +2,7 @@ using System; using System.IO; using System.Threading; using OpenMetaverse; +using OpenMetaverse.Assets; namespace OpenMetaverse.TestClient { diff --git a/Programs/examples/TestClient/Commands/Prims/ExportCommand.cs b/Programs/examples/TestClient/Commands/Prims/ExportCommand.cs index c2dc5db4..dd3cc310 100644 --- a/Programs/examples/TestClient/Commands/Prims/ExportCommand.cs +++ b/Programs/examples/TestClient/Commands/Prims/ExportCommand.cs @@ -4,6 +4,7 @@ using System.IO; using System.Threading; using OpenMetaverse; using OpenMetaverse.StructuredData; +using OpenMetaverse.Assets; namespace OpenMetaverse.TestClient { diff --git a/Programs/examples/TestClient/Commands/Prims/TexturesCommand.cs b/Programs/examples/TestClient/Commands/Prims/TexturesCommand.cs index e6920e56..4fcb6b4e 100644 --- a/Programs/examples/TestClient/Commands/Prims/TexturesCommand.cs +++ b/Programs/examples/TestClient/Commands/Prims/TexturesCommand.cs @@ -1,6 +1,7 @@ using System; using System.Collections.Generic; using OpenMetaverse; +using OpenMetaverse.Assets; namespace OpenMetaverse.TestClient { diff --git a/Programs/examples/groupmanager/frmGroupInfo.cs b/Programs/examples/groupmanager/frmGroupInfo.cs index b74c0465..40768b13 100644 --- a/Programs/examples/groupmanager/frmGroupInfo.cs +++ b/Programs/examples/groupmanager/frmGroupInfo.cs @@ -8,6 +8,7 @@ using System.Windows.Forms; using System.IO; using OpenMetaverse; using OpenMetaverse.Imaging; +using OpenMetaverse.Assets; namespace groupmanager {