mirror of
https://github.com/Leonmmcoset/CMLeonOS.git
synced 2026-03-03 15:30:27 +00:00
json
This commit is contained in:
@@ -589,6 +589,7 @@ namespace UniLua
|
||||
new NameFuncPair( LuaMathLib.LIB_NAME, LuaMathLib.OpenLib ),
|
||||
new NameFuncPair( LuaDebugLib.LIB_NAME, LuaDebugLib.OpenLib ),
|
||||
new NameFuncPair( LuaEncLib.LIB_NAME, LuaEncLib.OpenLib ),
|
||||
new NameFuncPair( LuaJsonLib.LIB_NAME, LuaJsonLib.OpenLib ),
|
||||
};
|
||||
|
||||
for( var i=0; i<define.Length; ++i)
|
||||
|
||||
526
UniLua/LuaJsonLib.cs
Normal file
526
UniLua/LuaJsonLib.cs
Normal file
@@ -0,0 +1,526 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
using StringBuilder = System.Text.StringBuilder;
|
||||
|
||||
namespace UniLua
|
||||
{
|
||||
internal static class LuaJsonLib
|
||||
{
|
||||
public const string LIB_NAME = "json";
|
||||
|
||||
private static readonly string[] ESCAPE_CHARS = new string[]
|
||||
{
|
||||
"\"", "\\", "/", "\b", "\f", "\n", "\r", "\t"
|
||||
};
|
||||
|
||||
public static int OpenLib(ILuaState lua)
|
||||
{
|
||||
NameFuncPair[] define = new NameFuncPair[]
|
||||
{
|
||||
new NameFuncPair("encode", Json_Encode),
|
||||
new NameFuncPair("decode", Json_Decode),
|
||||
new NameFuncPair("null", Json_Null),
|
||||
new NameFuncPair("parse", Json_Parse),
|
||||
new NameFuncPair("stringify", Json_Stringify)
|
||||
};
|
||||
|
||||
lua.L_NewLib(define);
|
||||
return 1;
|
||||
}
|
||||
|
||||
private static int Json_Encode(ILuaState lua)
|
||||
{
|
||||
lua.L_CheckAny(1);
|
||||
LuaType t = lua.Type(1);
|
||||
|
||||
if (t == LuaType.LUA_TNIL)
|
||||
{
|
||||
lua.PushString("null");
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (t == LuaType.LUA_TBOOLEAN)
|
||||
{
|
||||
lua.PushString(lua.ToBoolean(1) ? "true" : "false");
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (t == LuaType.LUA_TNUMBER)
|
||||
{
|
||||
lua.PushString(lua.ToNumber(1).ToString());
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (t == LuaType.LUA_TSTRING)
|
||||
{
|
||||
string s = lua.ToString(1);
|
||||
lua.PushString(JsonEscapeString(s));
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (t == LuaType.LUA_TTABLE)
|
||||
{
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.Append("{");
|
||||
|
||||
bool first = true;
|
||||
lua.PushNil();
|
||||
while (lua.Next(1))
|
||||
{
|
||||
if (!first)
|
||||
{
|
||||
sb.Append(",");
|
||||
}
|
||||
first = false;
|
||||
|
||||
string key = lua.ToString(-2);
|
||||
if (lua.Type(-1) == LuaType.LUA_TSTRING)
|
||||
{
|
||||
sb.Append("\"");
|
||||
sb.Append(JsonEscapeString(key));
|
||||
sb.Append("\":");
|
||||
}
|
||||
else
|
||||
{
|
||||
sb.Append(key);
|
||||
sb.Append(":");
|
||||
}
|
||||
|
||||
lua.PushValue(-1);
|
||||
int result = Json_Encode(lua);
|
||||
lua.Pop(1);
|
||||
|
||||
if (lua.Type(-1) == LuaType.LUA_TSTRING)
|
||||
{
|
||||
sb.Append("\"");
|
||||
sb.Append(JsonEscapeString(lua.ToString(-1)));
|
||||
}
|
||||
else
|
||||
{
|
||||
sb.Append(lua.ToString(-1));
|
||||
}
|
||||
}
|
||||
|
||||
sb.Append("}");
|
||||
lua.PushString(sb.ToString());
|
||||
return 1;
|
||||
}
|
||||
|
||||
lua.PushNil();
|
||||
return 1;
|
||||
}
|
||||
|
||||
private static int Json_Decode(ILuaState lua)
|
||||
{
|
||||
lua.L_CheckString(1);
|
||||
string json = lua.ToString(1).Trim();
|
||||
|
||||
if (json == "null" || json.Length == 0)
|
||||
{
|
||||
lua.PushNil();
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (json == "true")
|
||||
{
|
||||
lua.PushBoolean(true);
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (json == "false")
|
||||
{
|
||||
lua.PushBoolean(false);
|
||||
return 1;
|
||||
}
|
||||
|
||||
if ((json.StartsWith("\"") && json.EndsWith("\"")) ||
|
||||
(json.StartsWith("'") && json.EndsWith("'")))
|
||||
{
|
||||
string unquoted = json.Substring(1, json.Length - 2);
|
||||
lua.PushString(unquoted);
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (json.StartsWith("{") || json.StartsWith("["))
|
||||
{
|
||||
try
|
||||
{
|
||||
int pos = 0;
|
||||
object result = ParseJson(json, ref pos);
|
||||
PushLuaValue(lua, result);
|
||||
return 1;
|
||||
}
|
||||
catch
|
||||
{
|
||||
lua.PushNil();
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
if (char.IsDigit(json[0]))
|
||||
{
|
||||
double num = double.Parse(json);
|
||||
lua.PushNumber(num);
|
||||
return 1;
|
||||
}
|
||||
|
||||
lua.PushNil();
|
||||
return 1;
|
||||
}
|
||||
|
||||
private static object ParseJson(string json, ref int pos)
|
||||
{
|
||||
json = json.Trim();
|
||||
|
||||
if (json.StartsWith("{"))
|
||||
{
|
||||
return ParseJsonObject(json, ref pos);
|
||||
}
|
||||
else if (json.StartsWith("["))
|
||||
{
|
||||
return ParseJsonArray(json, ref pos);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
private static Dictionary<string, object> ParseJsonObject(string json, ref int pos)
|
||||
{
|
||||
Dictionary<string, object> dict = new Dictionary<string, object>();
|
||||
string content = json.Substring(1, json.Length - 2);
|
||||
int contentPos = 0;
|
||||
|
||||
while (contentPos < content.Length)
|
||||
{
|
||||
contentPos = SkipWhitespace(content, contentPos);
|
||||
|
||||
if (contentPos >= content.Length)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
if (content[contentPos] == '}')
|
||||
{
|
||||
contentPos++;
|
||||
break;
|
||||
}
|
||||
|
||||
string key = ParseJsonString(content, ref contentPos);
|
||||
contentPos = SkipWhitespace(content, contentPos);
|
||||
|
||||
if (contentPos >= content.Length || content[contentPos] != ':')
|
||||
{
|
||||
break;
|
||||
}
|
||||
contentPos++;
|
||||
|
||||
object value = ParseJsonValue(content, ref contentPos);
|
||||
if (key != null)
|
||||
{
|
||||
dict[key] = value;
|
||||
}
|
||||
|
||||
contentPos = SkipWhitespace(content, contentPos);
|
||||
if (contentPos < content.Length && content[contentPos] == ',')
|
||||
{
|
||||
contentPos++;
|
||||
}
|
||||
}
|
||||
|
||||
pos = contentPos;
|
||||
return dict;
|
||||
}
|
||||
|
||||
private static List<object> ParseJsonArray(string json, ref int pos)
|
||||
{
|
||||
List<object> list = new List<object>();
|
||||
string content = json.Substring(1, json.Length - 2);
|
||||
int contentPos = 0;
|
||||
|
||||
while (contentPos < content.Length)
|
||||
{
|
||||
contentPos = SkipWhitespace(content, contentPos);
|
||||
|
||||
if (contentPos >= content.Length)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
if (content[contentPos] == ']')
|
||||
{
|
||||
contentPos++;
|
||||
break;
|
||||
}
|
||||
|
||||
object value = ParseJsonValue(content, ref contentPos);
|
||||
if (value != null)
|
||||
{
|
||||
list.Add(value);
|
||||
}
|
||||
|
||||
contentPos = SkipWhitespace(content, contentPos);
|
||||
if (contentPos < content.Length && content[contentPos] == ',')
|
||||
{
|
||||
contentPos++;
|
||||
}
|
||||
}
|
||||
|
||||
pos = contentPos;
|
||||
return list;
|
||||
}
|
||||
|
||||
private static object ParseJsonValue(string content, ref int pos)
|
||||
{
|
||||
pos = SkipWhitespace(content, pos);
|
||||
|
||||
if (pos >= content.Length)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
char c = content[pos];
|
||||
|
||||
if (c == '{')
|
||||
{
|
||||
return ParseJsonObject(content, ref pos);
|
||||
}
|
||||
else if (c == '[')
|
||||
{
|
||||
return ParseJsonArray(content, ref pos);
|
||||
}
|
||||
else if (c == '"')
|
||||
{
|
||||
return ParseJsonString(content, ref pos);
|
||||
}
|
||||
else if (c == 't' || c == 'f' || c == 'n')
|
||||
{
|
||||
string keyword = "";
|
||||
while (pos < content.Length && char.IsLetter(content[pos]))
|
||||
{
|
||||
keyword += content[pos];
|
||||
pos++;
|
||||
}
|
||||
|
||||
if (keyword == "true")
|
||||
{
|
||||
return true;
|
||||
}
|
||||
else if (keyword == "false")
|
||||
{
|
||||
return false;
|
||||
}
|
||||
else if (keyword == "null")
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
else if (char.IsDigit(c) || c == '-')
|
||||
{
|
||||
string numStr = "";
|
||||
while (pos < content.Length && (char.IsDigit(content[pos]) || content[pos] == '-' || content[pos] == '.'))
|
||||
{
|
||||
numStr += content[pos];
|
||||
pos++;
|
||||
}
|
||||
|
||||
if (double.TryParse(numStr, out double num))
|
||||
{
|
||||
return num;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
private static string ParseJsonString(string content, ref int pos)
|
||||
{
|
||||
if (pos >= content.Length || content[pos] != '"')
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
pos++;
|
||||
|
||||
StringBuilder sb = new StringBuilder();
|
||||
while (pos < content.Length)
|
||||
{
|
||||
char c = content[pos];
|
||||
pos++;
|
||||
|
||||
if (c == '"')
|
||||
{
|
||||
break;
|
||||
}
|
||||
else if (c == '\\')
|
||||
{
|
||||
if (pos >= content.Length)
|
||||
{
|
||||
sb.Append('\\');
|
||||
break;
|
||||
}
|
||||
|
||||
pos++;
|
||||
char escapeChar = content[pos];
|
||||
pos++;
|
||||
|
||||
switch (escapeChar)
|
||||
{
|
||||
case '"':
|
||||
sb.Append('"');
|
||||
break;
|
||||
case '\\':
|
||||
sb.Append('\\');
|
||||
break;
|
||||
case '/':
|
||||
sb.Append('/');
|
||||
break;
|
||||
case 'b':
|
||||
sb.Append('\b');
|
||||
break;
|
||||
case 'f':
|
||||
sb.Append('\f');
|
||||
break;
|
||||
case 'n':
|
||||
sb.Append('\n');
|
||||
break;
|
||||
case 'r':
|
||||
sb.Append('\r');
|
||||
break;
|
||||
case 't':
|
||||
sb.Append('\t');
|
||||
break;
|
||||
case 'u':
|
||||
if (pos + 3 < content.Length)
|
||||
{
|
||||
string hex = content.Substring(pos, 4);
|
||||
if (int.TryParse(hex, System.Globalization.NumberStyles.HexNumber, null, out int code))
|
||||
{
|
||||
sb.Append((char)code);
|
||||
pos += 3;
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
sb.Append(escapeChar);
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
sb.Append(c);
|
||||
}
|
||||
}
|
||||
|
||||
return sb.ToString();
|
||||
}
|
||||
|
||||
private static int SkipWhitespace(string content, int pos)
|
||||
{
|
||||
while (pos < content.Length && char.IsWhiteSpace(content[pos]))
|
||||
{
|
||||
pos++;
|
||||
}
|
||||
return pos;
|
||||
}
|
||||
|
||||
private static void PushLuaValue(ILuaState lua, object value)
|
||||
{
|
||||
if (value == null)
|
||||
{
|
||||
lua.PushNil();
|
||||
}
|
||||
else if (value is bool)
|
||||
{
|
||||
lua.PushBoolean((bool)value);
|
||||
}
|
||||
else if (value is double)
|
||||
{
|
||||
lua.PushNumber((double)value);
|
||||
}
|
||||
else if (value is string)
|
||||
{
|
||||
lua.PushString((string)value);
|
||||
}
|
||||
else if (value is Dictionary<string, object>)
|
||||
{
|
||||
lua.NewTable();
|
||||
foreach (var kvp in (Dictionary<string, object>)value)
|
||||
{
|
||||
lua.PushString(kvp.Key);
|
||||
PushLuaValue(lua, kvp.Value);
|
||||
lua.SetField(-3, kvp.Key);
|
||||
}
|
||||
}
|
||||
else if (value is List<object>)
|
||||
{
|
||||
lua.NewTable();
|
||||
int index = 1;
|
||||
foreach (var item in (List<object>)value)
|
||||
{
|
||||
PushLuaValue(lua, item);
|
||||
lua.RawSetI(-2, index++);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static string JsonEscapeString(string s)
|
||||
{
|
||||
if (string.IsNullOrEmpty(s))
|
||||
{
|
||||
return "";
|
||||
}
|
||||
|
||||
StringBuilder sb = new StringBuilder();
|
||||
foreach (char c in s)
|
||||
{
|
||||
switch (c)
|
||||
{
|
||||
case '"':
|
||||
sb.Append("\\\"");
|
||||
break;
|
||||
case '\\':
|
||||
sb.Append("\\\\");
|
||||
break;
|
||||
case '\b':
|
||||
sb.Append("\\b");
|
||||
break;
|
||||
case '\f':
|
||||
sb.Append("\\f");
|
||||
break;
|
||||
case '\n':
|
||||
sb.Append("\\n");
|
||||
break;
|
||||
case '\r':
|
||||
sb.Append("\\r");
|
||||
break;
|
||||
case '\t':
|
||||
sb.Append("\\t");
|
||||
break;
|
||||
default:
|
||||
sb.Append(c);
|
||||
break;
|
||||
}
|
||||
}
|
||||
return sb.ToString();
|
||||
}
|
||||
|
||||
private static int Json_Null(ILuaState lua)
|
||||
{
|
||||
lua.PushNil();
|
||||
return 1;
|
||||
}
|
||||
|
||||
private static int Json_Parse(ILuaState lua)
|
||||
{
|
||||
return Json_Decode(lua);
|
||||
}
|
||||
|
||||
private static int Json_Stringify(ILuaState lua)
|
||||
{
|
||||
return Json_Encode(lua);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1086,7 +1086,54 @@ print(decoded)
|
||||
```
|
||||
|
||||
---
|
||||
## JSON 库
|
||||
|
||||
### json.encode(table)
|
||||
将 Lua 表编码为 JSON 字符串。
|
||||
|
||||
```lua
|
||||
local data = {name = "John", age = 30}
|
||||
local jsonStr = json.encode(data)
|
||||
print(jsonStr)
|
||||
```
|
||||
|
||||
### json.decode(string)
|
||||
将 JSON 字符串解码为 Lua 表。
|
||||
|
||||
```lua
|
||||
local jsonStr = '{"name": "John", "age": 30}'
|
||||
local data = json.decode(jsonStr)
|
||||
print(data.name)
|
||||
print(data.age)
|
||||
```
|
||||
|
||||
### json.null()
|
||||
返回 null 值。
|
||||
|
||||
```lua
|
||||
local nullValue = json.null()
|
||||
print(nullValue)
|
||||
```
|
||||
|
||||
### json.parse(string)
|
||||
解析 JSON 字符串(同 decode)。
|
||||
|
||||
```lua
|
||||
local jsonStr = '{"name": "John", "age": 30}'
|
||||
local data = json.parse(jsonStr)
|
||||
print(data.name)
|
||||
```
|
||||
|
||||
### json.stringify(table)
|
||||
将 Lua 表转换为 JSON 字符串(同 encode)。
|
||||
|
||||
```lua
|
||||
local data = {name = "John", age = 30}
|
||||
local jsonStr = json.stringify(data)
|
||||
print(jsonStr)
|
||||
```
|
||||
|
||||
---
|
||||
## 包库 (package)
|
||||
|
||||
### package.loaded
|
||||
|
||||
Reference in New Issue
Block a user