diff --git a/OpenSim/Framework/SLUtil.cs b/OpenSim/Framework/SLUtil.cs index 92491050b3..027fc0e163 100644 --- a/OpenSim/Framework/SLUtil.cs +++ b/OpenSim/Framework/SLUtil.cs @@ -25,13 +25,9 @@ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ +using OpenMetaverse; using System; using System.Collections.Generic; -using System.IO; -using System.Reflection; -using System.Xml; -using log4net; -using OpenMetaverse; namespace OpenSim.Framework { @@ -251,106 +247,270 @@ namespace OpenSim.Framework #endregion SL / file extension / content-type conversions + private class NotecardReader + { + private string rawInput; + private int lineNumber; + + public int LineNumber + { + get + { + return lineNumber; + } + } + + public NotecardReader(string _rawInput) + { + rawInput = (string)_rawInput.Clone(); + lineNumber = 0; + } + + public string getLine() + { + if(rawInput.Length == 0) + { + throw new NotANotecardFormatException(lineNumber + 1); + } + + int pos = rawInput.IndexOf('\n'); + if(pos < 0) + { + pos = rawInput.Length; + } + + /* cut line from rest */ + ++lineNumber; + string line = rawInput.Substring(0, pos); + if (pos + 1 >= rawInput.Length) + { + rawInput = string.Empty; + } + else + { + rawInput = rawInput.Substring(pos + 1); + } + /* clean up line from double spaces and tabs */ + line = line.Replace("\t", " "); + while(line.IndexOf(" ") >= 0) + { + line = line.Replace(" ", " "); + } + return line.Replace("\r", "").Trim(); + } + + public string getBlock(int length) + { + /* cut line from rest */ + if(length > rawInput.Length) + { + throw new NotANotecardFormatException(lineNumber); + } + string line = rawInput.Substring(0, length); + rawInput = rawInput.Substring(length); + return line; + } + } + + public class NotANotecardFormatException : Exception + { + public int lineNumber; + public NotANotecardFormatException(int _lineNumber) + : base() + { + lineNumber = _lineNumber; + } + } + + private static void skipSection(NotecardReader reader) + { + if (reader.getLine() != "{") + throw new NotANotecardFormatException(reader.LineNumber); + + string line; + while ((line = reader.getLine()) != "}") + { + if(line.IndexOf('{')>=0) + { + throw new NotANotecardFormatException(reader.LineNumber); + } + } + } + + private static void skipInventoryItem(NotecardReader reader) + { + if (reader.getLine() != "{") + throw new NotANotecardFormatException(reader.LineNumber); + + string line; + while((line = reader.getLine()) != "}") + { + string[] data = line.Split(' '); + if(data.Length == 0) + { + continue; + } + if(data[0] == "permissions") + { + skipSection(reader); + } + else if(data[0] == "sale_info") + { + skipSection(reader); + } + else if (line.IndexOf('{') >= 0) + { + throw new NotANotecardFormatException(reader.LineNumber); + } + } + } + + private static void skipInventoryItems(NotecardReader reader) + { + if(reader.getLine() != "{") + { + throw new NotANotecardFormatException(reader.LineNumber); + } + + string line; + while((line = reader.getLine()) != "}") + { + string[] data = line.Split(' '); + if(data.Length == 0) + { + continue; + } + + if(data[0] == "inv_item") + { + skipInventoryItem(reader); + } + else if (line.IndexOf('{') >= 0) + { + throw new NotANotecardFormatException(reader.LineNumber); + } + + } + } + + private static void skipInventory(NotecardReader reader) + { + if (reader.getLine() != "{") + throw new NotANotecardFormatException(reader.LineNumber); + + string line; + while((line = reader.getLine()) != "}") + { + string[] data = line.Split(' '); + if(data[0] == "count") + { + int count = Int32.Parse(data[1]); + for(int i = 0; i < count; ++i) + { + skipInventoryItems(reader); + } + } + else if (line.IndexOf('{') >= 0) + { + throw new NotANotecardFormatException(reader.LineNumber); + } + } + } + + private static string readNotecardText(NotecardReader reader) + { + if (reader.getLine() != "{") + throw new NotANotecardFormatException(reader.LineNumber); + + string notecardString = string.Empty; + string line; + while((line = reader.getLine()) != "}") + { + string[] data = line.Split(' '); + if (data.Length == 0) + { + continue; + } + + if (data[0] == "LLEmbeddedItems") + { + skipInventory(reader); + } + else if(data[0] == "Text" && data.Length == 3) + { + int length = Int32.Parse(data[2]); + notecardString = reader.getBlock(length); + } + else if (line.IndexOf('{') >= 0) + { + throw new NotANotecardFormatException(reader.LineNumber); + } + + } + return notecardString; + } + + private static string readNotecard(byte[] rawInput) + { + string rawIntermedInput = string.Empty; + + /* make up a Raw Encoding here */ + foreach(byte c in rawInput) + { + char d = (char)c; + rawIntermedInput += d; + } + + NotecardReader reader = new NotecardReader(rawIntermedInput); + string line; + try + { + line = reader.getLine(); + } + catch(Exception) + { + return System.Text.Encoding.UTF8.GetString(rawInput); + } + string[] versioninfo = line.Split(' '); + if(versioninfo.Length < 3) + { + return System.Text.Encoding.UTF8.GetString(rawInput); + } + else if(versioninfo[0] != "Linden" || versioninfo[1] != "text") + { + return System.Text.Encoding.UTF8.GetString(rawInput); + } + else + { + /* now we actually decode the Encoding, before we needed it in raw */ + string o = readNotecardText(reader); + byte[] a = new byte[o.Length]; + for(int i = 0; i < o.Length; ++i) + { + a[i] = (byte)o[i]; + } + return System.Text.Encoding.UTF8.GetString(a); + } + } + /// /// Parse a notecard in Linden format to a string of ordinary text. /// /// /// - public static string ParseNotecardToString(string rawInput) + public static string ParseNotecardToString(byte[] rawInput) { - string[] output = ParseNotecardToList(rawInput).ToArray(); - -// foreach (string line in output) -// m_log.DebugFormat("[PARSE NOTECARD]: ParseNotecardToString got line {0}", line); - - return string.Join("\n", output); + return readNotecard(rawInput); } - + /// /// Parse a notecard in Linden format to a list of ordinary lines. /// /// /// - public static List ParseNotecardToList(string rawInput) + public static string[] ParseNotecardToArray(byte[] rawInput) { - string[] input; - int idx = 0; - int level = 0; - List output = new List(); - string[] words; - - //The Linden format always ends with a } after the input data. - //Strip off trailing } so there is nothing after the input data. - int i = rawInput.LastIndexOf("}"); - rawInput = rawInput.Remove(i, rawInput.Length-i); - input = rawInput.Replace("\r", "").Split('\n'); - - while (idx < input.Length) - { - if (input[idx] == "{") - { - level++; - idx++; - continue; - } - - if (input[idx]== "}") - { - level--; - idx++; - continue; - } - - switch (level) - { - case 0: - words = input[idx].Split(' '); // Linden text ver - // Notecards are created *really* empty. Treat that as "no text" (just like after saving an empty notecard) - if (words.Length < 3) - return output; - - int version = int.Parse(words[3]); - if (version != 2) - return output; - break; - case 1: - words = input[idx].Split(' '); - if (words[0] == "LLEmbeddedItems") - break; - if (words[0] == "Text") - { - idx++; //Now points to first line of notecard text - - //Number of lines in notecard. - int lines = input.Length - idx; - int line = 0; - - while (line < lines) - { -// m_log.DebugFormat("[PARSE NOTECARD]: Adding line {0}", input[idx]); - output.Add(input[idx]); - idx++; - line++; - } - - return output; - } - break; - case 2: - words = input[idx].Split(' '); // count - if (words[0] == "count") - { - int c = int.Parse(words[1]); - if (c > 0) - return output; - break; - } - break; - } - idx++; - } - - return output; + return readNotecard(rawInput).Replace("\r", "").Split('\n'); } } } diff --git a/OpenSim/Region/OptionalModules/Scripting/JsonStore/JsonStoreScriptModule.cs b/OpenSim/Region/OptionalModules/Scripting/JsonStore/JsonStoreScriptModule.cs index b69676b12e..edf51a2dab 100644 --- a/OpenSim/Region/OptionalModules/Scripting/JsonStore/JsonStoreScriptModule.cs +++ b/OpenSim/Region/OptionalModules/Scripting/JsonStore/JsonStoreScriptModule.cs @@ -595,11 +595,15 @@ namespace OpenSim.Region.OptionalModules.Scripting.JsonStore try { - string jsondata = SLUtil.ParseNotecardToString(Encoding.UTF8.GetString(a.Data)); + string jsondata = SLUtil.ParseNotecardToString(a.Data); int result = m_store.SetValue(storeID, path, jsondata,true) ? 1 : 0; m_comms.DispatchReply(scriptID, result, "", reqID.ToString()); return; } + catch(SLUtil.NotANotecardFormatException e) + { + m_log.WarnFormat("[JsonStoreScripts]: Notecard parsing failed; assetId {0} at line number {1}", assetID.ToString(), e.lineNumber); + } catch (Exception e) { m_log.WarnFormat("[JsonStoreScripts]: Json parsing failed; {0}", e.Message); diff --git a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs index bb8ec9ccb2..6a30da21d0 100644 --- a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs +++ b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs @@ -11632,9 +11632,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api return; } - string data = Encoding.UTF8.GetString(a.Data); - //m_log.Debug(data); - NotecardCache.Cache(id, data); + NotecardCache.Cache(id, a.Data); AsyncCommands.DataserverPlugin.DataserverReply(reqIdentifier, NotecardCache.GetLines(id).ToString()); }); @@ -11688,7 +11686,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api string data = Encoding.UTF8.GetString(a.Data); //m_log.Debug(data); - NotecardCache.Cache(id, data); + NotecardCache.Cache(id, a.Data); AsyncCommands.DataserverPlugin.DataserverReply( reqIdentifier, NotecardCache.GetLine(assetID, line, m_notecardLineReadCharsMax)); }); @@ -12461,10 +12459,10 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api public DateTime lastRef; } - protected static Dictionary m_Notecards = + private static Dictionary m_Notecards = new Dictionary(); - public static void Cache(UUID assetID, string text) + public static void Cache(UUID assetID, byte[] text) { CheckCache(); @@ -12475,7 +12473,14 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api Notecard nc = new Notecard(); nc.lastRef = DateTime.Now; - nc.text = SLUtil.ParseNotecardToList(text).ToArray(); + try + { + nc.text = SLUtil.ParseNotecardToArray(text); + } + catch(SLUtil.NotANotecardFormatException) + { + nc.text = new string[0]; + } m_Notecards[assetID] = nc; } } diff --git a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/OSSL_Api.cs b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/OSSL_Api.cs index 10ddf14089..3afebe237a 100644 --- a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/OSSL_Api.cs +++ b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/OSSL_Api.cs @@ -1926,8 +1926,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api if (a == null) return UUID.Zero; - string data = Encoding.UTF8.GetString(a.Data); - NotecardCache.Cache(assetID, data); + NotecardCache.Cache(assetID, a.Data); }; return assetID;