corrected script notecard parser. It now handles notecards with inventory as well.

Signed-off-by: BlueWall <jamesh@bluewallgroup.com>
inv-download
ft@noemail 2015-03-04 00:17:24 +01:00 committed by BlueWall
parent c02636b6f3
commit fb48ee1cb6
4 changed files with 270 additions and 102 deletions

View File

@ -25,13 +25,9 @@
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/ */
using OpenMetaverse;
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.IO;
using System.Reflection;
using System.Xml;
using log4net;
using OpenMetaverse;
namespace OpenSim.Framework namespace OpenSim.Framework
{ {
@ -251,106 +247,270 @@ namespace OpenSim.Framework
#endregion SL / file extension / content-type conversions #endregion SL / file extension / content-type conversions
private class NotecardReader
{
private string rawInput;
private int lineNumber;
public int LineNumber
{
get
{
return lineNumber;
}
}
public NotecardReader(string _rawInput)
{
rawInput = (string)_rawInput.Clone();
lineNumber = 0;
}
public string getLine()
{
if(rawInput.Length == 0)
{
throw new NotANotecardFormatException(lineNumber + 1);
}
int pos = rawInput.IndexOf('\n');
if(pos < 0)
{
pos = rawInput.Length;
}
/* cut line from rest */
++lineNumber;
string line = rawInput.Substring(0, pos);
if (pos + 1 >= rawInput.Length)
{
rawInput = string.Empty;
}
else
{
rawInput = rawInput.Substring(pos + 1);
}
/* clean up line from double spaces and tabs */
line = line.Replace("\t", " ");
while(line.IndexOf(" ") >= 0)
{
line = line.Replace(" ", " ");
}
return line.Replace("\r", "").Trim();
}
public string getBlock(int length)
{
/* cut line from rest */
if(length > rawInput.Length)
{
throw new NotANotecardFormatException(lineNumber);
}
string line = rawInput.Substring(0, length);
rawInput = rawInput.Substring(length);
return line;
}
}
public class NotANotecardFormatException : Exception
{
public int lineNumber;
public NotANotecardFormatException(int _lineNumber)
: base()
{
lineNumber = _lineNumber;
}
}
private static void skipSection(NotecardReader reader)
{
if (reader.getLine() != "{")
throw new NotANotecardFormatException(reader.LineNumber);
string line;
while ((line = reader.getLine()) != "}")
{
if(line.IndexOf('{')>=0)
{
throw new NotANotecardFormatException(reader.LineNumber);
}
}
}
private static void skipInventoryItem(NotecardReader reader)
{
if (reader.getLine() != "{")
throw new NotANotecardFormatException(reader.LineNumber);
string line;
while((line = reader.getLine()) != "}")
{
string[] data = line.Split(' ');
if(data.Length == 0)
{
continue;
}
if(data[0] == "permissions")
{
skipSection(reader);
}
else if(data[0] == "sale_info")
{
skipSection(reader);
}
else if (line.IndexOf('{') >= 0)
{
throw new NotANotecardFormatException(reader.LineNumber);
}
}
}
private static void skipInventoryItems(NotecardReader reader)
{
if(reader.getLine() != "{")
{
throw new NotANotecardFormatException(reader.LineNumber);
}
string line;
while((line = reader.getLine()) != "}")
{
string[] data = line.Split(' ');
if(data.Length == 0)
{
continue;
}
if(data[0] == "inv_item")
{
skipInventoryItem(reader);
}
else if (line.IndexOf('{') >= 0)
{
throw new NotANotecardFormatException(reader.LineNumber);
}
}
}
private static void skipInventory(NotecardReader reader)
{
if (reader.getLine() != "{")
throw new NotANotecardFormatException(reader.LineNumber);
string line;
while((line = reader.getLine()) != "}")
{
string[] data = line.Split(' ');
if(data[0] == "count")
{
int count = Int32.Parse(data[1]);
for(int i = 0; i < count; ++i)
{
skipInventoryItems(reader);
}
}
else if (line.IndexOf('{') >= 0)
{
throw new NotANotecardFormatException(reader.LineNumber);
}
}
}
private static string readNotecardText(NotecardReader reader)
{
if (reader.getLine() != "{")
throw new NotANotecardFormatException(reader.LineNumber);
string notecardString = string.Empty;
string line;
while((line = reader.getLine()) != "}")
{
string[] data = line.Split(' ');
if (data.Length == 0)
{
continue;
}
if (data[0] == "LLEmbeddedItems")
{
skipInventory(reader);
}
else if(data[0] == "Text" && data.Length == 3)
{
int length = Int32.Parse(data[2]);
notecardString = reader.getBlock(length);
}
else if (line.IndexOf('{') >= 0)
{
throw new NotANotecardFormatException(reader.LineNumber);
}
}
return notecardString;
}
private static string readNotecard(byte[] rawInput)
{
string rawIntermedInput = string.Empty;
/* make up a Raw Encoding here */
foreach(byte c in rawInput)
{
char d = (char)c;
rawIntermedInput += d;
}
NotecardReader reader = new NotecardReader(rawIntermedInput);
string line;
try
{
line = reader.getLine();
}
catch(Exception)
{
return System.Text.Encoding.UTF8.GetString(rawInput);
}
string[] versioninfo = line.Split(' ');
if(versioninfo.Length < 3)
{
return System.Text.Encoding.UTF8.GetString(rawInput);
}
else if(versioninfo[0] != "Linden" || versioninfo[1] != "text")
{
return System.Text.Encoding.UTF8.GetString(rawInput);
}
else
{
/* now we actually decode the Encoding, before we needed it in raw */
string o = readNotecardText(reader);
byte[] a = new byte[o.Length];
for(int i = 0; i < o.Length; ++i)
{
a[i] = (byte)o[i];
}
return System.Text.Encoding.UTF8.GetString(a);
}
}
/// <summary> /// <summary>
/// Parse a notecard in Linden format to a string of ordinary text. /// Parse a notecard in Linden format to a string of ordinary text.
/// </summary> /// </summary>
/// <param name="rawInput"></param> /// <param name="rawInput"></param>
/// <returns></returns> /// <returns></returns>
public static string ParseNotecardToString(string rawInput) public static string ParseNotecardToString(byte[] rawInput)
{ {
string[] output = ParseNotecardToList(rawInput).ToArray(); return readNotecard(rawInput);
// foreach (string line in output)
// m_log.DebugFormat("[PARSE NOTECARD]: ParseNotecardToString got line {0}", line);
return string.Join("\n", output);
} }
/// <summary> /// <summary>
/// Parse a notecard in Linden format to a list of ordinary lines. /// Parse a notecard in Linden format to a list of ordinary lines.
/// </summary> /// </summary>
/// <param name="rawInput"></param> /// <param name="rawInput"></param>
/// <returns></returns> /// <returns></returns>
public static List<string> ParseNotecardToList(string rawInput) public static string[] ParseNotecardToArray(byte[] rawInput)
{ {
string[] input; return readNotecard(rawInput).Replace("\r", "").Split('\n');
int idx = 0;
int level = 0;
List<string> output = new List<string>();
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;
} }
} }
} }

View File

@ -595,11 +595,15 @@ namespace OpenSim.Region.OptionalModules.Scripting.JsonStore
try 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; int result = m_store.SetValue(storeID, path, jsondata,true) ? 1 : 0;
m_comms.DispatchReply(scriptID, result, "", reqID.ToString()); m_comms.DispatchReply(scriptID, result, "", reqID.ToString());
return; 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) catch (Exception e)
{ {
m_log.WarnFormat("[JsonStoreScripts]: Json parsing failed; {0}", e.Message); m_log.WarnFormat("[JsonStoreScripts]: Json parsing failed; {0}", e.Message);

View File

@ -11632,9 +11632,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
return; return;
} }
string data = Encoding.UTF8.GetString(a.Data); NotecardCache.Cache(id, a.Data);
//m_log.Debug(data);
NotecardCache.Cache(id, data);
AsyncCommands.DataserverPlugin.DataserverReply(reqIdentifier, NotecardCache.GetLines(id).ToString()); 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); string data = Encoding.UTF8.GetString(a.Data);
//m_log.Debug(data); //m_log.Debug(data);
NotecardCache.Cache(id, data); NotecardCache.Cache(id, a.Data);
AsyncCommands.DataserverPlugin.DataserverReply( AsyncCommands.DataserverPlugin.DataserverReply(
reqIdentifier, NotecardCache.GetLine(assetID, line, m_notecardLineReadCharsMax)); reqIdentifier, NotecardCache.GetLine(assetID, line, m_notecardLineReadCharsMax));
}); });
@ -12461,10 +12459,10 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
public DateTime lastRef; public DateTime lastRef;
} }
protected static Dictionary<UUID, Notecard> m_Notecards = private static Dictionary<UUID, Notecard> m_Notecards =
new Dictionary<UUID, Notecard>(); new Dictionary<UUID, Notecard>();
public static void Cache(UUID assetID, string text) public static void Cache(UUID assetID, byte[] text)
{ {
CheckCache(); CheckCache();
@ -12475,7 +12473,14 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
Notecard nc = new Notecard(); Notecard nc = new Notecard();
nc.lastRef = DateTime.Now; 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; m_Notecards[assetID] = nc;
} }
} }

View File

@ -1926,8 +1926,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
if (a == null) if (a == null)
return UUID.Zero; return UUID.Zero;
string data = Encoding.UTF8.GetString(a.Data); NotecardCache.Cache(assetID, a.Data);
NotecardCache.Cache(assetID, data);
}; };
return assetID; return assetID;