diff options
author | nebadon | 2011-12-11 23:25:12 -0700 |
---|---|---|
committer | nebadon | 2011-12-11 23:25:12 -0700 |
commit | 8ae824ff095605c5889828503cec09006ac07cc0 (patch) | |
tree | c87dcf50a53184b21e30b287200d903db9f17948 /OpenSim/Region | |
parent | Implement handler for TeleportCancel inbound packet (diff) | |
download | opensim-SC_OLD-8ae824ff095605c5889828503cec09006ac07cc0.zip opensim-SC_OLD-8ae824ff095605c5889828503cec09006ac07cc0.tar.gz opensim-SC_OLD-8ae824ff095605c5889828503cec09006ac07cc0.tar.bz2 opensim-SC_OLD-8ae824ff095605c5889828503cec09006ac07cc0.tar.xz |
Mantis 5816: osParseJSON Decoding Problems
osParseJSON uses hand-crafted decoding that has two issues
* does not seem to handle top-level JSON lists
* does not seem to handle unicode text
thanks otakup0pe!
Diffstat (limited to 'OpenSim/Region')
3 files changed, 72 insertions, 191 deletions
diff --git a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/OSSL_Api.cs b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/OSSL_Api.cs index f3206ac..503b5d0 100644 --- a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/OSSL_Api.cs +++ b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/OSSL_Api.cs | |||
@@ -1552,209 +1552,83 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api | |||
1552 | return m_ScriptEngine.World.GetSimulatorVersion(); | 1552 | return m_ScriptEngine.World.GetSimulatorVersion(); |
1553 | } | 1553 | } |
1554 | 1554 | ||
1555 | public Hashtable osParseJSON(string JSON) | 1555 | private Hashtable osdToHashtable(OSDMap map) |
1556 | { | ||
1557 | Hashtable result = new Hashtable(); | ||
1558 | foreach (KeyValuePair<string, OSD> item in map) { | ||
1559 | result.Add(item.Key, osdToObject(item.Value)); | ||
1560 | } | ||
1561 | return result; | ||
1562 | } | ||
1563 | |||
1564 | private ArrayList osdToArray(OSDArray list) | ||
1565 | { | ||
1566 | ArrayList result = new ArrayList(); | ||
1567 | foreach ( OSD item in list ) { | ||
1568 | result.Add(osdToObject(item)); | ||
1569 | } | ||
1570 | return result; | ||
1571 | } | ||
1572 | |||
1573 | private Object osdToObject(OSD decoded) | ||
1574 | { | ||
1575 | if ( decoded is OSDString ) { | ||
1576 | return (string) decoded.AsString(); | ||
1577 | } else if ( decoded is OSDInteger ) { | ||
1578 | return (int) decoded.AsInteger(); | ||
1579 | } else if ( decoded is OSDReal ) { | ||
1580 | return (float) decoded.AsReal(); | ||
1581 | } else if ( decoded is OSDBoolean ) { | ||
1582 | return (bool) decoded.AsBoolean(); | ||
1583 | } else if ( decoded is OSDMap ) { | ||
1584 | return osdToHashtable((OSDMap) decoded); | ||
1585 | } else if ( decoded is OSDArray ) { | ||
1586 | return osdToArray((OSDArray) decoded); | ||
1587 | } else { | ||
1588 | return null; | ||
1589 | } | ||
1590 | } | ||
1591 | |||
1592 | public Object osParseJSONNew(string JSON) | ||
1556 | { | 1593 | { |
1557 | CheckThreatLevel(ThreatLevel.None, "osParseJSON"); | 1594 | CheckThreatLevel(ThreatLevel.None, "osParseJSON"); |
1558 | 1595 | ||
1559 | m_host.AddScriptLPS(1); | 1596 | m_host.AddScriptLPS(1); |
1560 | 1597 | ||
1561 | // see http://www.json.org/ for more details on JSON | ||
1562 | |||
1563 | string currentKey = null; | ||
1564 | Stack objectStack = new Stack(); // objects in JSON can be nested so we need to keep a track of this | ||
1565 | Hashtable jsondata = new Hashtable(); // the hashtable to be returned | ||
1566 | int i = 0; | ||
1567 | try | 1598 | try |
1568 | { | 1599 | { |
1600 | OSD decoded = OSDParser.DeserializeJson(JSON); | ||
1601 | return osdToObject(decoded); | ||
1602 | } | ||
1603 | catch(Exception e) | ||
1604 | { | ||
1605 | OSSLError("osParseJSONNew: Problems decoding JSON string " + JSON + " : " + e.Message) ; | ||
1606 | return null; | ||
1607 | } | ||
1608 | } | ||
1569 | 1609 | ||
1570 | // iterate through the serialised stream of tokens and store at the right depth in the hashtable | 1610 | public Hashtable osParseJSON(string JSON) |
1571 | // the top level hashtable may contain more nested hashtables within it each containing an objects representation | 1611 | { |
1572 | for (i = 0; i < JSON.Length; i++) | 1612 | CheckThreatLevel(ThreatLevel.None, "osParseJSON"); |
1573 | { | ||
1574 | |||
1575 | // m_log.Debug(""+JSON[i]); | ||
1576 | switch (JSON[i]) | ||
1577 | { | ||
1578 | case '{': | ||
1579 | // create hashtable and add it to the stack or array if we are populating one, we can have a lot of nested objects in JSON | ||
1580 | |||
1581 | Hashtable currentObject = new Hashtable(); | ||
1582 | if (objectStack.Count == 0) // the stack should only be empty for the first outer object | ||
1583 | { | ||
1584 | |||
1585 | objectStack.Push(jsondata); | ||
1586 | } | ||
1587 | else if (objectStack.Peek().ToString() == "System.Collections.ArrayList") | ||
1588 | { | ||
1589 | // add it to the parent array | ||
1590 | ((ArrayList)objectStack.Peek()).Add(currentObject); | ||
1591 | objectStack.Push(currentObject); | ||
1592 | } | ||
1593 | else | ||
1594 | { | ||
1595 | // add it to the parent hashtable | ||
1596 | ((Hashtable)objectStack.Peek()).Add(currentKey,currentObject); | ||
1597 | objectStack.Push(currentObject); | ||
1598 | } | ||
1599 | |||
1600 | // clear the key | ||
1601 | currentKey = null; | ||
1602 | break; | ||
1603 | |||
1604 | case '}': | ||
1605 | // pop the hashtable off the stack | ||
1606 | objectStack.Pop(); | ||
1607 | break; | ||
1608 | |||
1609 | case '"':// string boundary | ||
1610 | |||
1611 | string tokenValue = ""; | ||
1612 | i++; // move to next char | ||
1613 | |||
1614 | // just loop through until the next quote mark storing the string, ignore quotes with pre-ceding \ | ||
1615 | while (JSON[i] != '"') | ||
1616 | { | ||
1617 | tokenValue += JSON[i]; | ||
1618 | |||
1619 | // handle escaped double quotes \" | ||
1620 | if (JSON[i] == '\\' && JSON[i+1] == '"') | ||
1621 | { | ||
1622 | tokenValue += JSON[i+1]; | ||
1623 | i++; | ||
1624 | } | ||
1625 | i++; | ||
1626 | |||
1627 | } | ||
1628 | |||
1629 | // ok we've got a string, if we've got an array on the top of the stack then we store it | ||
1630 | if (objectStack.Peek().ToString() == "System.Collections.ArrayList") | ||
1631 | { | ||
1632 | ((ArrayList)objectStack.Peek()).Add(tokenValue); | ||
1633 | } | ||
1634 | else if (currentKey == null) // no key stored and its not an array this must be a key so store it | ||
1635 | { | ||
1636 | currentKey = tokenValue; | ||
1637 | } | ||
1638 | else | ||
1639 | { | ||
1640 | // we have a key so lets store this value | ||
1641 | ((Hashtable)objectStack.Peek()).Add(currentKey,tokenValue); | ||
1642 | // now lets clear the key, we're done with it and moving on | ||
1643 | currentKey = null; | ||
1644 | } | ||
1645 | |||
1646 | break; | ||
1647 | |||
1648 | case ':':// key : value separator | ||
1649 | // just ignore | ||
1650 | break; | ||
1651 | |||
1652 | case ' ':// spaces | ||
1653 | // just ignore | ||
1654 | break; | ||
1655 | |||
1656 | case '[': // array start | ||
1657 | ArrayList currentArray = new ArrayList(); | ||
1658 | |||
1659 | if (objectStack.Peek().ToString() == "System.Collections.ArrayList") | ||
1660 | { | ||
1661 | ((ArrayList)objectStack.Peek()).Add(currentArray); | ||
1662 | } | ||
1663 | else | ||
1664 | { | ||
1665 | ((Hashtable)objectStack.Peek()).Add(currentKey,currentArray); | ||
1666 | // clear the key | ||
1667 | currentKey = null; | ||
1668 | } | ||
1669 | objectStack.Push(currentArray); | ||
1670 | |||
1671 | break; | ||
1672 | |||
1673 | case ',':// seperator | ||
1674 | // just ignore | ||
1675 | break; | ||
1676 | |||
1677 | case ']'://Array end | ||
1678 | // pop the array off the stack | ||
1679 | objectStack.Pop(); | ||
1680 | break; | ||
1681 | |||
1682 | case 't': // we've found a character start not in quotes, it must be a boolean true | ||
1683 | |||
1684 | if (objectStack.Peek().ToString() == "System.Collections.ArrayList") | ||
1685 | { | ||
1686 | ((ArrayList)objectStack.Peek()).Add(true); | ||
1687 | } | ||
1688 | else | ||
1689 | { | ||
1690 | ((Hashtable)objectStack.Peek()).Add(currentKey,true); | ||
1691 | currentKey = null; | ||
1692 | } | ||
1693 | |||
1694 | //advance the counter to the letter 'e' | ||
1695 | i = i + 3; | ||
1696 | break; | ||
1697 | |||
1698 | case 'f': // we've found a character start not in quotes, it must be a boolean false | ||
1699 | |||
1700 | if (objectStack.Peek().ToString() == "System.Collections.ArrayList") | ||
1701 | { | ||
1702 | ((ArrayList)objectStack.Peek()).Add(false); | ||
1703 | } | ||
1704 | else | ||
1705 | { | ||
1706 | ((Hashtable)objectStack.Peek()).Add(currentKey,false); | ||
1707 | currentKey = null; | ||
1708 | } | ||
1709 | //advance the counter to the letter 'e' | ||
1710 | i = i + 4; | ||
1711 | break; | ||
1712 | |||
1713 | case '\n':// carriage return | ||
1714 | // just ignore | ||
1715 | break; | ||
1716 | |||
1717 | case '\r':// carriage return | ||
1718 | // just ignore | ||
1719 | break; | ||
1720 | |||
1721 | default: | ||
1722 | // ok here we're catching all numeric types int,double,long we might want to spit these up mr accurately | ||
1723 | // but for now we'll just do them as strings | ||
1724 | |||
1725 | string numberValue = ""; | ||
1726 | |||
1727 | // just loop through until the next known marker quote mark storing the string | ||
1728 | while (JSON[i] != '"' && JSON[i] != ',' && JSON[i] != ']' && JSON[i] != '}' && JSON[i] != ' ') | ||
1729 | { | ||
1730 | numberValue += "" + JSON[i++]; | ||
1731 | } | ||
1732 | |||
1733 | i--; // we want to process this caracter that marked the end of this string in the main loop | ||
1734 | 1613 | ||
1735 | // ok we've got a string, if we've got an array on the top of the stack then we store it | 1614 | m_host.AddScriptLPS(1); |
1736 | if (objectStack.Peek().ToString() == "System.Collections.ArrayList") | ||
1737 | { | ||
1738 | ((ArrayList)objectStack.Peek()).Add(numberValue); | ||
1739 | } | ||
1740 | else | ||
1741 | { | ||
1742 | // we have a key so lets store this value | ||
1743 | ((Hashtable)objectStack.Peek()).Add(currentKey,numberValue); | ||
1744 | // now lets clear the key, we're done with it and moving on | ||
1745 | currentKey = null; | ||
1746 | } | ||
1747 | 1615 | ||
1748 | break; | 1616 | Object decoded = osParseJSONNew(JSON); |
1749 | } | 1617 | |
1618 | if ( decoded is Hashtable ) { | ||
1619 | return (Hashtable) decoded; | ||
1620 | } else if ( decoded is ArrayList ) { | ||
1621 | ArrayList decoded_list = (ArrayList) decoded; | ||
1622 | Hashtable fakearray = new Hashtable(); | ||
1623 | int i = 0; | ||
1624 | for ( i = 0; i < decoded_list.Count ; i++ ) { | ||
1625 | fakearray.Add(i, decoded_list[i]); | ||
1750 | } | 1626 | } |
1627 | return fakearray; | ||
1628 | } else { | ||
1629 | OSSLError("osParseJSON: unable to parse JSON string " + JSON); | ||
1630 | return null; | ||
1751 | } | 1631 | } |
1752 | catch(Exception) | ||
1753 | { | ||
1754 | OSSLError("osParseJSON: The JSON string is not valid " + JSON) ; | ||
1755 | } | ||
1756 | |||
1757 | return jsondata; | ||
1758 | } | 1632 | } |
1759 | 1633 | ||
1760 | /// <summary> | 1634 | /// <summary> |
diff --git a/OpenSim/Region/ScriptEngine/Shared/Api/Interface/IOSSL_Api.cs b/OpenSim/Region/ScriptEngine/Shared/Api/Interface/IOSSL_Api.cs index 3221833..00ca070 100644 --- a/OpenSim/Region/ScriptEngine/Shared/Api/Interface/IOSSL_Api.cs +++ b/OpenSim/Region/ScriptEngine/Shared/Api/Interface/IOSSL_Api.cs | |||
@@ -25,6 +25,7 @@ | |||
25 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | 25 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
26 | */ | 26 | */ |
27 | 27 | ||
28 | using System; | ||
28 | using System.Collections; | 29 | using System.Collections; |
29 | using OpenSim.Region.ScriptEngine.Interfaces; | 30 | using OpenSim.Region.ScriptEngine.Interfaces; |
30 | 31 | ||
@@ -140,6 +141,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api.Interfaces | |||
140 | 141 | ||
141 | string osGetScriptEngineName(); | 142 | string osGetScriptEngineName(); |
142 | string osGetSimulatorVersion(); | 143 | string osGetSimulatorVersion(); |
144 | Object osParseJSONNew(string JSON); | ||
143 | Hashtable osParseJSON(string JSON); | 145 | Hashtable osParseJSON(string JSON); |
144 | 146 | ||
145 | void osMessageObject(key objectUUID,string message); | 147 | void osMessageObject(key objectUUID,string message); |
diff --git a/OpenSim/Region/ScriptEngine/Shared/Api/Runtime/OSSL_Stub.cs b/OpenSim/Region/ScriptEngine/Shared/Api/Runtime/OSSL_Stub.cs index 9e7c8da..0d7d5ea 100644 --- a/OpenSim/Region/ScriptEngine/Shared/Api/Runtime/OSSL_Stub.cs +++ b/OpenSim/Region/ScriptEngine/Shared/Api/Runtime/OSSL_Stub.cs | |||
@@ -396,6 +396,11 @@ namespace OpenSim.Region.ScriptEngine.Shared.ScriptBase | |||
396 | { | 396 | { |
397 | return m_OSSL_Functions.osParseJSON(JSON); | 397 | return m_OSSL_Functions.osParseJSON(JSON); |
398 | } | 398 | } |
399 | |||
400 | public Object osParseJSONNew(string JSON) | ||
401 | { | ||
402 | return m_OSSL_Functions.osParseJSONNew(JSON); | ||
403 | } | ||
399 | 404 | ||
400 | public void osMessageObject(key objectUUID,string message) | 405 | public void osMessageObject(key objectUUID,string message) |
401 | { | 406 | { |