Vendor libs/hump, sfxrlua, json4lua, narrator as real files

These were committed as empty submodule gitlinks with no .gitmodules,
so the folders were never populated and the game could not load
(require of libs/hump/timer, libs/sfxrlua/sfxr, narrator.narrator).
Checked out each at its pinned commit and vendored the files, matching
the existing bundled-libs convention. Removed the junk libs/libs/ tree.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
Your Name 2026-08-11 11:37:09 -04:00
parent e73f63b5d4
commit 03532d29e4
219 changed files with 20254 additions and 252 deletions

@ -1 +0,0 @@
Subproject commit a0da807dca77baf07d287631f5ad41a9097fc25c

52
libs/json4lua/README.md Normal file
View file

@ -0,0 +1,52 @@
# json4lua
JSON and JSONRPC for Lua
# Installation #
```
luarocks install --server=http://rocks.moonscript.org/manifests/amrhassan --local json4Lua
```
# JSON Usage #
## Encoding ##
```lua
json = require('json')
print(json.encode({ 1, 2, 'fred', {first='mars',second='venus',third='earth'} }))
```
```json
[1,2,"fred", {"first":"mars","second":"venus","third":"earth"}]
```
## Decoding ##
```lua
json = require("json")
testString = [[ { "one":1 , "two":2, "primes":[2,3,5,7] } ]]
decoded = json.decode(testString)
table.foreach(decoded, print)
print ("Primes are:")
table.foreach(decoded.primes,print)
```
```
one 1
two 2
primes table: 0032B928
Primes are:
1 2
2 3
3 5
4 7
```
# JSONRPC Usage #
```lua
json = require('json')
require("json.rpc")
server = json.rpc.proxy("http://jsolait.net/testj.py")
result, error = server.echo('Test echo!')
print(result)
```
```
Test echo!
```

4
libs/json4lua/doc/INSTALL.txt Executable file
View file

@ -0,0 +1,4 @@
INSTALLATION
============
See INSTALLATION section in doc/index.html

21
libs/json4lua/doc/LICENCE.txt Executable file
View file

@ -0,0 +1,21 @@
The MIT License
Copyright (c) 2009 Craig Mason-Jones
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.

5
libs/json4lua/doc/README.txt Executable file
View file

@ -0,0 +1,5 @@
===================================================================================================================
== README.txt
===================================================================================================================
Please see doc/index.html

4
libs/json4lua/doc/VERSION.txt Executable file
View file

@ -0,0 +1,4 @@
JSON4Lua and JSONRPC4Lua
Version 1.0.0
4 March 2015
http://github.com/craigmj/json4lua/

View file

@ -0,0 +1,187 @@
<html>
<head>
<title>JSON4Lua and JSONRPC4Lua</title>
<style type="text/css">
body {
font-family: Arial, Helvetica, Geneva;
font-size: 10pt;
}
.copyright {
color: #999999;
font-size: 8pt;
text-align:center;
}
.navBar {
border-left: 1px solid lightgray;
border-right: 1px solid lightgray;
border-bottom: 1px solid lightgray;
margin-top:5px;
margin-bottom: 5px;
}
.navBar h1 {
background-image: url('pics/lunartone.gif');
background-color: #e0c088;
color: white;
font-size: 9pt;
margin: 0px;
padding: 4px;
}
.navBar .navItem a {
color: #999999;
font-size: 8pt;
padding: 2px 2px 2px 10px;
text-decoration:none;
}
.navBar .navItem a:hover {
color: #ff9900;
text-decoration: underline;
}
.titleBar {
border-bottom: 2px dotted gray;
font-size: 20pt;
font-weight: bold;
margin-bottom: 15px;
width: 100%;
}
.workArea {
border: 1px none lightgray;
font-family: Times New Roman;
padding: 8px;
padding-left: 15px;
}
.workArea a {
font-weight: bold;
text-decoration: none;
}
.workArea a:hover {
color: #ff9900;
text-decoration: underline;
}
.workArea .downloadTable {
border: 1px solid lightgray;
padding: 0px;
margin: 0px;
}
.workArea .downloadTable * th {
background-color: #e0c088;
background-image: url('pics/lunartone.gif');
color: white;
}
.workArea .downloadTable * tr {
border: 1px solid lightgray;
}
.workArea .downloadTable * td {
vertical-align: top;
}
.workArea * dt {
font-size: 12pt;
margin-top: 10px;
}
.workArea * .example {
background-color: #ffffcc;
border: 1px dashed lightgray;
padding: 10px;
}
.workArea h1 {
font-size: 16pt;
font-weight: bold;
}
.workArea h2 {
font-size: 14pt;
font-weight: normal;
color: gray;
}
</style>
<body>
<table border="0">
<tr>
<td valign="top">
<img src="pics/json4lua.gif"><p/>
<!-- NAVIGATION BARS -->
<div class="navBar">
<h1>Home Page</h1>
<div class="navItem"><a href="index.html#news">Latest News</a></div>
<div class="navItem"><a href="index.html#introduction">Introduction</a></div>
<div class="navItem"><a href="index.html#licence">Licence</a></div>
<div class="navItem"><a href="index.html#requirements">Requirements</a></div>
<div class="navItem"><a href="index.html#download">Download</a></div>
<div class="navItem"><a href="index.html#installation">Installation</a></div>
<div class="navItem"><a href="index.html#usage">Usage &amp; Reference</a></div>
<div class="navItem"><a href="index.html#roadmap">History &amp; Roadmap</a></div>
</div> <!-- end of navigation bar: This Site -->
<div class="navBar">
<h1>json.luaforge</h1>
<div class="navItem"><a href="http://luaforge.net/projects/json/">Summary</a></div>
<div class="navItem"><a href="http://luaforge.net/forum/?group_id=143">Forums</a></div>
<div class="navItem"><a href="http://luaforge.net/tracker/?group_id=143">Tracker</a></div>
<div class="navItem"><a href="http://luaforge.net/news/?group_id=143">News</a></div>
<!--<div class="navItem"><a href="http://luaforge.net/scm/?group_id=143">CVS</a></div>-->
<div class="navItem"><a href="http://luaforge.net/frs/?group_id=143">Files</a></div>
</div> <!-- end of navigation bar: json.luaforge -->
<div class="navBar">
<h1>Lua</h1>
<div class="navItem"><a href="http://www.lua.org/">Lua</a></div>
<div class="navItem"><a href="http://www.luaforge.net/">Lua Forge</a></div>
<div class="navItem"><a href="http://www.keplerproject.org/cgilua/">CGI Lua</a></div>
<div class="navItem"><a href="http://www.keplerproject.org/compat/">Lua compat-5.1</a></div>
<div class="navItem"><a href="http://www.cs.princeton.edu/~diego/professional/luasocket/">Lua Socket 2.0</a></div>
<div class="navItem"><a href="http://www.keplerproject.org/xavante/">Xavante</a></div>
</div> <!-- end of navigation bar: Lua Resources -->
<div class="navBar">
<h1>JSON</h1>
<div class="navItem"><a href="http://www.json.org/">json.org</a></div>
<div class="navItem"><a href="http://www.json-rpc.org/">json-rpc.org</a></div>
</div> <!-- end of navigation bar: Lua Resources -->
</td>
<!-- MAIN WORK AREA -->
<td valign="top" class="workArea">
<div class="titleBar">Patching CGILua to handle <code>text/plain</code></div>
<!-- cgilua_patch.html -->
JSON RPC (both the JSONRPC4Lua implementation and the <a href="http://www.jsolait.net/">jsolait Javascript</a> implementation) send the http request with a Content-Type of <code>text/plain</code>.<p/>
CGILua 5.0 does not accept <code>text/plain</code> content, and will generate an error of 'Unsupported Media Type: text/plain'.<p/>
This is easily patched in CGILua 5.0 by making the following change to <code>cgilua/post.lua</code>, line 286:<p/>
Change:<pre>
elseif strfind (contenttype, "text/xml") then
</pre>
to
<pre>
elseif strfind (contenttype, "text/xml") or strfind (contenttype, "text/plain") then
</pre>
This makes CGILua handle <code>text/plain</code> as it does <code>text/xml</code>, without parsing the incoming POST data.<p/>
<b>Please note:</b> I have requested the maintainers of CGILua to make this change to CGILua, whereafter this patch will no longer be required.
</td>
</tr>
<tr>
<td colspan="2" class="copyright">&copy; 2005 Craig Mason-Jones</td>
</tr>
</table>
</body>
</html>

394
libs/json4lua/doc/index.html Executable file
View file

@ -0,0 +1,394 @@
<html>
<head>
<title>JSON4Lua and JSONRPC4Lua</title>
<style type="text/css">
body {
font-family: Arial, Helvetica, Geneva;
font-size: 10pt;
}
.copyright {
color: #999999;
font-size: 8pt;
text-align:center;
}
.navBar {
border-left: 1px solid lightgray;
border-right: 1px solid lightgray;
border-bottom: 1px solid lightgray;
margin-top:5px;
margin-bottom: 5px;
}
.navBar h1 {
background-image: url('pics/lunartone.gif');
background-color: #e0c088;
color: white;
font-size: 9pt;
margin: 0px;
padding: 4px;
}
.navBar .navItem a {
color: #999999;
font-size: 8pt;
padding: 2px 2px 2px 10px;
text-decoration:none;
}
.navBar .navItem a:hover {
color: #ff9900;
text-decoration: underline;
}
.titleBar {
border-bottom: 2px dotted gray;
font-size: 20pt;
font-weight: bold;
margin-bottom: 15px;
width: 100%;
}
.workArea {
border: 1px none lightgray;
font-family: Times New Roman;
padding: 8px;
padding-left: 15px;
}
.workArea a {
font-weight: bold;
text-decoration: none;
}
.workArea a:hover {
color: #ff9900;
text-decoration: underline;
}
.workArea .downloadTable {
border: 1px solid lightgray;
padding: 0px;
margin: 0px;
}
.workArea .downloadTable * th {
background-color: #e0c088;
background-image: url('pics/lunartone.gif');
color: white;
}
.workArea .downloadTable * tr {
border: 1px solid lightgray;
}
.workArea .downloadTable * td {
vertical-align: top;
}
.workArea * dt {
font-size: 12pt;
margin-top: 10px;
}
.workArea * .example {
background-color: #ffffcc;
border: 1px dashed lightgray;
padding: 10px;
}
.workArea h1 {
font-size: 16pt;
font-weight: bold;
}
.workArea h2 {
font-size: 14pt;
font-weight: normal;
color: gray;
}
</style>
<body>
<table border="0">
<tr>
<td valign="top">
<img src="pics/json4lua.gif"><p/>
<!-- NAVIGATION BARS -->
<div class="navBar">
<h1>This Page</h1>
<div class="navItem"><a href="#news">Latest News</a></div>
<div class="navItem"><a href="#introduction">Introduction</a></div>
<div class="navItem"><a href="#licence">Licence</a></div>
<div class="navItem"><a href="#requirements">Requirements</a></div>
<div class="navItem"><a href="#download">Download</a></div>
<div class="navItem"><a href="#installation">Installation</a></div>
<div class="navItem"><a href="#usage">Usage &amp; Reference</a>
<div class="navItem" style="margin-left: 4px"><a href="#json_decode">decode</a></div>
<div class="navItem" style="margin-left: 4px"><a href="#json_encode">encode</a></div>
<div class="navItem" style="margin-left: 4px"><a href="#json_null">null</a></div>
<div class="navItem" style="margin-left: 4px"><a href="#json_rpc_call">rpc.call</a></div>
<div class="navItem" style="margin-left: 4px"><a href="#json_rpc_proxy">rpc.proxy</a></div>
<div class="navItem" style="margin-left: 4px"><a href="#json_rpcserver_serve">rpcserver.serve</a></div>
</div>
<div class="navItem"><a href="#roadmap">History &amp; Roadmap</a></div>
</div> <!-- end of navigation bar: This Site -->
<div class="navBar">
<h1>json.luaforge</h1>
<div class="navItem"><a href="http://luaforge.net/projects/json/">Summary</a></div>
<div class="navItem"><a href="http://luaforge.net/forum/?group_id=143">Forums</a></div>
<div class="navItem"><a href="http://luaforge.net/tracker/?group_id=143">Tracker</a></div>
<div class="navItem"><a href="http://luaforge.net/news/?group_id=143">News</a></div>
<!--<div class="navItem"><a href="http://luaforge.net/scm/?group_id=143">CVS</a></div>-->
<div class="navItem"><a href="http://luaforge.net/frs/?group_id=143">Files</a></div>
</div> <!-- end of navigation bar: json.luaforge -->
<div class="navBar">
<h1>Lua</h1>
<div class="navItem"><a href="http://www.lua.org/">Lua</a></div>
<div class="navItem"><a href="http://www.luaforge.net/">Lua Forge</a></div>
<div class="navItem"><a href="http://www.keplerproject.org/cgilua/">CGI Lua</a></div>
<div class="navItem"><a href="http://www.keplerproject.org/compat/">Lua compat-5.1</a></div>
<div class="navItem"><a href="http://www.cs.princeton.edu/~diego/professional/luasocket/">Lua Socket 2.0</a></div>
<div class="navItem"><a href="http://www.keplerproject.org/xavante/">Xavante</a></div>
</div> <!-- end of navigation bar: Lua Resources -->
<div class="navBar">
<h1>JSON</h1>
<div class="navItem"><a href="http://www.json.org/">json.org</a></div>
<div class="navItem"><a href="http://www.json-rpc.org/">json-rpc.org</a></div>
</div> <!-- end of navigation bar: Lua Resources -->
</td>
<!-- MAIN WORK AREA -->
<td valign="top" class="workArea">
<div class="titleBar">JSON4Lua and JSONRPC4Lua</div>
<!-- ***************** LATEST NEWS ***************** -->
<h1><a name="news"></a>Latest News</h1>
<p><small>(2009-08-06)</small> We've changed the JSON4Lua and JSONRPC4Lua licence from the GPL to the MIT licence, like Lua itself.</p>
<p>
The 0.9.20 release fixes a bug in Lua 5.1 operation, introduces a <a href="#json_null"><code>json.null</code></a> value to force null values in JSON encodings, improves performance (over 50% faster on some tests), and permits <code>/* comments */</code> in the JSON string being decoded.
</p>
<!-- ***************** INTRODUCTION ***************** -->
<h1><a name="introduction"></a>Introduction</h1>
JSON4Lua and JSONRPC4Lua implement <a href="http://www.json.org">JSON (JavaScript Object Notation)</a> encoding and decoding and a <a href="http://www.json-rpc.org/">JSON-RPC-over-http</a> client for <a href="http://www.lua.org/">Lua</a>.<p/>
JSON is JavaScript Object Notation, a simple encoding of Javascript-like objects that is ideal for lightweight transmission of relatively weakly-typed data.
A sub-package of JSON4Lua is JSONRPC4Lua, which provides a simple JSON-RPC-over-http client and server (in a CGILua environment) for Lua. Please seen the documentation below for JSONRPC4Lua.
<!-- ***************** LICENCE ***************** -->
<h1><a name="licence"></a>Licence</h1>
JSON4Lua is licensed under the MIT Consortium licence like Lua itself. Please see <a href="LICENCE.txt">LICENCE.txt</a> for details.<p/>
<!-- ***************** REQUIREMENTS ***************** -->
<a name="requirements"></a><h1>Requirements</h1>
JSON4Lua is a pure-Lua module that is Lua 5.0 compatible (if you have <a href="http://www.keplerproject.org/compat/">compat-5.1</a> for Lua 5.0). JSON4Lua also works (perfectly, I hope) under Lua 5.1, which is where I largely use it nowadays. Since Lua is platform independent, so is JSON4Lua.<p/>
The JSON4RPC sub-module requires <a href="http://www.cs.princeton.edu/~diego/professional/luasocket/">Lua Socket 2.0</a>. It uses <code>socket.http</code> for for the RPC over http connection. Socket 2.0 includes <code>ltn12</code>, which is also used by JSON4RPC.<p />
To use <code>json.rpcserver</code> you need a <a href="http://www.keplerproject.org/cgilua/">CGILua</a> enabled webserver. However, a quick <a href="cgilua_patch.html">patch</a> is required in CGILua 5.0 to support JSON-RPC.
<!-- ***************** START OF DOWNLOAD SECTION ***************** -->
<h1><a name="download"></a>Download</h1>
JSON4Lua is hosted on <a href="http://www.luaforge.net">LuaForge</a>.
<table cols="2" class="downloadTable">
<tr><th>Version</th><th>Date</th><th>Notes</th></tr>
<tr><td><a href="http://luaforge.net/frs/?group_id=143">0.9.30</a></td><td>6 August 2009</td><td>
Changed to MIT Licence.
</td></tr>
<tr><td><a href="http://luaforge.net/frs/?group_id=143">0.9.20</a></td><td>4 January 2006</td><td>
Introduction of local Lua functions for private functions (removed _ function prefix). <br />
Fixed Lua 5.1 compatibility issues.<br />
Introduced <code>json.null</code> to have null values in associative arrays.<br />
Performance improvement (more than 50% on some tests) through <code>table.concat</code> rather than <code>..</code> operator.<br/>
<code>json.decode</code> now ignores <code>/* */</code> comments in the JSON string.<br />
</td></tr>
<tr><td><a href="http://luaforge.net/frs/?group_id=143">0.9.10</a></td><td>20 December 2005</td><td>
Fixes bug with array representation when nil / null values occur in the array.<br />
Adds content-type header of <code>text/plain</code> to JSON RPC http requests.<br />
Introduces <code>json.rpcserver</code> module with simple JSON RPC enablement for Lua objects.<br />
Moved the <code>json.lua</code> file into the <code>json</code> directory. Ensure, therefore, that your <code>LUA_PATH</code> contains a module-finding form like <code>LUA_PATH = c:\proj\lua\?\?.lua;?.lua</code>.<br/>
</td></tr>
<tr>
<td><a href="http://luaforge.net/frs/?group_id=143">0.9.01</a></td>
<td>19 December 2005</td>
<td>Minor corrections to documentation.</td>
</tr>
<tr>
<td><a href="http://luaforge.net/frs/?group_id=143">0.9.00</a></td>
<td>19 December 2005</td>
<td>First release</td>
</tr>
</table>
<!-- END OF DOWNLOAD SECTION -->
<!-- ***************** START OF INSTALLATION SECTION ***************** -->
<h1><a name="installation"></a>Installation</h1>
As of version 0.9.10, all the JSON4Lua files are contained in the <code>json</code> subdirectory in the distribution zip.<p />
Simply copy the <code>json</code> subdirectory so that it is in your Lua path.<p />
Ensure that your <code>LUA_PATH</code> variable permits module resolution of the form <code>?/?.lua</code>.<p />
<b>Example</b>
<div class="example">
</div>
<h2>Using Windows</h2>
Under Windows, set your Lua path as (my Lua installation is in <code>c:\proj\lua\</code>): <p/>
<code>
set LUA_PATH=c:\proj\lua\?.lua;c:\proj\lua\?\?.lua;?.lua
</code><p/>
For compat-5.1.lua to start when Lua starts (if you're using Lua 5.0), you also need:<p/>
<code>
set LUA_INIT=@c:\proj\lua\compat-5.1.lua
</code><p />
You probably also want to set your library path:<p/>
<code>set LUA_CPATH=c:\proj\lua\lib\?.dll;?.dll</code>
<!------------------------ USAGE AND REFERENCE -------------------->
<h1><a name="usage"></a>Usage &amp; Reference</h1>
The following functions in <b>JSON4Lua</b> and <b>JSONRPC4Lua</b> are of interest:<p />
<dl>
<dt><a name="json_encode"></a><code>string <b>json.encode</b>( lua_object )</code></dt>
<dd>Returns the Lua object JSON encoded into a string.<p/>
<b>Example</b>
<div class="example">
<code>
json = require("json")<br/>
print (json.encode( { 1, 2, 'fred', {first='mars',second='venus',third='earth'} } ))
</code><p/>
prints<p/><code> [1,2,"fred", {"first":"mars","second":"venus","third","earth"}]</code>
</div>
</dd>
<dt><a name="json_decode"></a><code>lua_object <b>json.decode</b>( json_string )</code></dt>
<dd>Decodes the JSON encoded data structure, and returns a Lua object with the appropriate data.<p/>
<b>Example</b>
<div class="example">
<code>
json = require("json")<br/>
testString = [[ { "one":1 , "two":2, "primes":[2,3,5,7] } ]]<br/>
o = json.decode(testString)<br/>
table.foreach(o,print)<br />
print ("Primes are:")<br />
table.foreach(o.primes,print)
</code><p/>
prints:<p/>
<pre>
one 1
two 2
primes table: 0032B928
Primes are:
1 2
2 3
3 5
4 7</pre>
</div></dd>
<dt><a name="json_null"></a><code><b>json.null</b></code></dt>
<dd>Returns a unique value that will be encoded as a <code>null</code> in a JSON encoding.
<p>This is necessary in one situation. In Lua, if a key in a table has a <code>nil</code> value, the key is simply discarded (since any non-existent key has a nil value). The encoding of arrays has been built to manage this nil-values in arrays, but associative arrays provide a problem. Consider:
<div class="example"><pre>t = { user="test", password=nil }</pre></div>
Since Lua simply discards the <code>password</code> key, JSON4Lua encodes this as the JSON string
<div class="example"><pre>{"user":"test"}</pre></div>
If, for some reason, your JSON RPC Server requires a defined <code>null</code> value, use the following code:
<div class="example"><pre>t = { user="test", password=json.null }</pre></div>
This will now correctly encode to:
<div class="example"><pre>{"user":"test","password":null}</pre></div>
Incidentally, <code>json.null</code> is simply a function that returns itself, so that you can use either <code>json.null</code> or <code>json.null()</code> as you fancy.
</dd>
<dt><a name="json_rpc_call"></a><code>result, error <b>json.rpc.call</b> ( url, method, ...)</code></dt>
<dd>Calls the named method on the given url with the arg parameters. Returns the result and the error. If <code>error</code> is <code>nil</code>, no error occurred.<p/>
<b>Example</b>
<div class="example">
<pre>require ("json.rpc")
result, error = json.rpc.call("http://jsolait.net/testj.py","echo","Test echo!")
print(result)</pre>
<p />prints<p />
<pre>Test echo!</pre>
</div>
</dd>
<dt><a name="json_rpc_proxy"></a><code>proxyServer = <b>json.rpc.proxy</b> (url)</code></dt>
<dd>Creates a proxy server object on which JSON-RPC calls can be made. Each call will return the <code>result, error</code>. If <code>error</code> is <code>nil</code>, no error occurred.<p/>
<b>Example</b>
<div class="example">
<pre>
require ("json.rpc")
server = json.rpc.proxy("http://jsolait.net/testj.py")
result, error = server.echo('Test echo!')
print(result)</pre>
<p />prints<p />
<pre>Test echo!</pre>
</div>
</dd>
<dt><a name="json_rpcserver_serve"></a><code><b>json.rpcserver.serve</b>(object[, packReturn])</code></dt>
<dd>
Handles an incoming CGILua request as a JSON RPC request and serves the request from
the given object.
<p />The optional <code>packReturn</code> parameter, if set <code>true</code>, will, if the requested
method returns more than one value, pack these returned values into an array. If only a single value
is returned, it is not packed into an array. If <code>packReturn</code> is <code>false</code> (or not set), only the first
return value from the requested method will be returned. This is necessitated since the JSON protocol does not permit a method call to return more than a single value.
<p/>
<code>serve</code> returns nothing.<p/>
<b>Example</b>
<div class="example">
<pre>
--
-- jsonrpc.lua
-- Installed in a CGILua webserver environment (with necessary CGI Lua 5.0 patch)
--
require ('json.rpcserver')
-- The Lua class that is to serve JSON RPC requests
local myServer = {
echo = function (msg) return msg end,
average = function(...)
local total=0
local count=0
for i=1, table.getn(arg) do
total = total + arg[i]
count = count + 1
end
return { average= total/count, sum = total, n=count }
end
}
json.rpcserver.serve(myServer)
</pre>
An example of using this JSON RPC server from a Lua file:
<pre>
require ('json.rpc')
local server = json.rpc.proxy('http://www.myserver.com/jsonrpc.lua')
table.foreach(server.average(10,15,23), print)
</pre>
Prints:
<pre>
average 16
sum 48
n 3
</pre>
</div>
</dd>
</dl>
<!-- ***************** HISTORY AND ROADMAP ***************** -->
<h1><a name="roadmap"></a>History &amp; Roadmap</h1>
The downloads sections details the versions and their related histories. I will wait for Lua 5.1 to be final (expected late January) before making the JSON4Lua module beta. If no serious bugs or objections are encountered, I will make the module 1.0 on 1 April 2006 (to coincide with April Fool's day!)
</td>
</tr>
<tr>
<td colspan="2" class="copyright">&copy; 2005, 2006 Craig Mason-Jones</td>
</tr>
</table>
</body>
</html>

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 312 B

View file

@ -0,0 +1,23 @@
--[[
JSON4Lua example script.
Demonstrates the simple functionality of the json module.
]]--
json = require('json')
-- Object to JSON encode
test = {
one='first',two='second',three={2,3,5}
}
jsonTest = json.encode(test)
print('JSON encoded test is: ' .. jsonTest)
-- Now JSON decode the json string
result = json.decode(jsonTest)
print ("The decoded table result:")
table.foreach(result,print)
print ("The decoded table result.three")
table.foreach(result.three, print)

View file

@ -0,0 +1,21 @@
--
-- jsonrpc.lua
-- Installed in a CGILua webserver environment (with necessary CGI Lua 5.0 patch)
--
require ('json.rpcserver')
-- The Lua class that is to serve JSON RPC requests
local myServer = {
echo = function (msg) return msg end,
average = function(...)
local total=0
local count=0
for i=1, table.getn(arg) do
total = total + arg[i]
count = count + 1
end
return { average= total/count, sum = total, n=count }
end
}
json.rpcserver.serve(myServer)

223
libs/json4lua/examples/tests.lua Executable file
View file

@ -0,0 +1,223 @@
--[[
Some basic tests for JSON4Lua.
]]--
--- Compares two tables for being data-identical.
function compareData(a,b)
if (type(a)=='string' or type(a)=='number' or type(a)=='boolean' or type(a)=='nil') then return a==b end
-- After basic data types, we're only interested in tables
if (type(a)~='table') then return true end
-- Check that a has everything b has
for k,v in pairs(b) do
if (not compareData( a[k], v ) ) then return false end
end
for k,v in pairs(a) do
if (not compareData( v, b[k] ) ) then return false end
end
return true
end
---
-- Checks that our compareData function works properly
function testCompareData()
s = "name"
r = "name"
assert(compareData(s,r))
assert(not compareData('fred',s))
assert(not compareData(nil, s))
assert(not compareData("123",123))
assert(not compareData(false, nil))
assert(compareData(true, true))
assert(compareData({1,2,3},{1,2,3}))
assert(compareData({'one',2,'three'},{'one',2,'three'}))
assert(not compareData({'one',2,4},{4,2,'one'}))
assert(compareData({one='ichi',two='nichi',three='san'}, {three='san',two='nichi',one='ichi'}))
s = { one={1,2,3}, two={one='hitotsu',two='futatsu',three='mitsu'} }
assert(compareData(s,s))
t = { one={1,2,3}, two={one='een',two='twee',three='drie'} }
assert(not compareData(s,t))
end
testCompareData()
--
--
-- Performs some perfunctory tests on JSON module
function testJSON4Lua()
json = require('json')
if nil then
-- Test encodeString
s = [["\"
]]
r = json._encodeString(s)
assert(r=='\\"\\\\\\"\\n')
s = [["""\\\"]]
r = json._encodeString(s)
assert(r==[[\"\"\"\\\\\\\"]])
end
-- Test encode for basic strings (complicated strings)
s = [[Hello, Lua!]]
r = json.encode(s)
assert(r=='"Hello, Lua!"')
s = [["\"
]]
r = json.encode(s)
assert(r=='\"\\"\\\\\\"\\n\"')
s = [["""\\\"]]
r = json.encode(s)
assert(r==[["\"\"\"\\\\\\\""]])
-- Test encode for numeric values
s = 23
r = json.encode(s)
assert(r=='23')
s=48.123
r = json.encode(s)
assert(r=='48.123')
-- Test encode for boolean values
assert(json.encode(true)=='true')
assert(json.encode(false)=='false')
assert(json.encode(nil)=='null')
-- Test encode for arrays
s = {1,2,3}
r = json.encode(s)
assert(r=="[1,2,3]")
s = {9,9,9}
r = json.encode(s)
assert(r=="[9,9,9]")
-- Complex array test
s = { 2, 'joe', false, nil, 'hi' }
r = json.encode(s)
assert(r=='[2,"joe",false,null,"hi"]')
-- Test encode for tables
s = {Name='Craig',email='craig@lateral.co.za',age=35}
r = json.encode(s)
-- NB: This test can fail because of order: need to test further once
-- decoding is supported.
-- assert(r==[[{"age":35,"Name":"Craig","email":"craig@lateral.co.za"}]])
-- Test encoding tables with numeric (string) indexes
s = {}
s['1']='One'
r = json.encode(s)
-- print("r = ", r)
assert(r=='{"1":"One"}')
s['2']= {One='Uno'}
r = json.encode(s)
assert(compareData(json.decode(r), s))
-- Test decode_scanWhitespace
if nil then
s = " \n \r \t "
e = json._decode_scanWhitespace(s,1)
assert(e==string.len(s)+1)
s = " \n\r\t4"
assert(json._decode_scanWhitespace(s,1)==5)
-- Test decode_scanString
s = [["Test"]]
r,e = json._decode_scanString(s,1)
assert(r=='Test' and e==7)
s = [["This\nis a \"test"]]
r = json._decode_scanString(s,1)
assert(r=="This\nis a \"test")
s = [["Test\u00A7\\"]]
r,e = json._decode_scanString(s,1)
assert(r=="Test\xC2\xA7\\" and e==9)
-- Test decode_scanNumber
s = [[354]]
r,e = json._decode_scanNumber(s,1)
assert(r==354 and e==4)
s = [[ 4565.23 AND OTHER THINGS ]]
r,e = json._decode_scanNumber(s,2)
assert(r==4565.23 and e==9)
s = [[ -23.22 and ]]
r,e = json._decode_scanNumber(s,2)
assert(r==-23.22 and e==8)
-- Test decode_scanConstant
s = "true"
r,e = json._decode_scanConstant(s,1)
assert(r==true and e==5)
s = " false "
r,e = json._decode_scanConstant(s,3)
assert(r==false and e==8)
s = "1null6"
r,e = json._decode_scanConstant(s,2)
assert(r==nil and e==6)
-- Test decode_scanArray
s = "[1,2,3]"
r,e = json._decode_scanArray(s,1)
assert(compareData(r,{1,2,3}))
s = [[[ 1 , 3 ,5 , "Fred" , true, false, null, -23 ] ]]
r,e = json._decode_scanArray(s,1)
assert(compareData(r, {1,3,5,'Fred',true,false,nil,-23} ) )
s = "[3,5,null,7,9]"
r,e = json._decode_scanArray(s,1)
assert(compareData(r, {3,5,nil,7,9}))
s = "[3,5,null,7,9,null,null]"
r,e = json._decode_scanArray(s,1)
assert(compareData(r, {3,5,nil,7,9,nil,nil}))
end
s = [["Test\u00A7\\\""]]
r,e = json.decode(s)
assert(r=="Test\xC2\xA7\\\"", r)
-- Test decode_scanObject
s = [[ {"one":1, "two":2, "three":"three", "four":true} ]]
r,e = json.decode(s)
-- for x,y in pairs(r) do
-- print(x,y)
-- end
assert(compareData(r,{one=1,two=2,three='three',four=true}))
s = [[ { "one" : { "first":1,"second":2,"third":3}, "two":2, "three":false } ]]
r,e = json.decode(s)
assert(compareData(r, {one={first=1,second=2,third=3},two=2,three=false}))
s = [[ { "primes" : [2,3,5,7,9], "user":{"name":"craig","age":35,"programs_lua":true},
"lua_is_great":true } ]]
r,e = json.decode(s)
assert(compareData(r, {primes={2,3,5,7,9},user={name='craig',age=35,programs_lua=true},lua_is_great=true}))
-- Test json.null management
t = { 1,2,json.null,4 }
assert( json.encode(t)=="[1,2,null,4]" )
t = {x=json.null }
r = json.encode(t)
assert( json.encode(t) == '{"x":null}' )
-- Test comment decoding
s = [[ /* A comment
that spans
a few lines
*/
"test"
]]
r,e = json.decode(s)
assert(r=='test',"Comment decoding failed")
-- Per error reported by M.Hund, with incorrect decoding of string-numbered tables
s = {}
subt = {a="a",b="b",c="c"}
s['1'] = subt
s['2'] = subt
s['3'] = subt
r = json.decode('{"1":{"a":"a","b":"b","c":"c"},"2":{"a":"a","b":"b","c":"c"},"3":{"a":"a","b":"b","c":"c"}}')
assert(compareData(s, r))
end
testJSON4Lua()
print("JSON4Lua tests completed successfully")

View file

@ -0,0 +1,46 @@
--[[
Some Time Trails for the JSON4Lua package
]]--
require('json')
require('os')
require('table')
local t1 = os.clock()
local jstr
local v
for i=1,100 do
local t = {}
for j=1,500 do
table.insert(t,j)
end
for j=1,500 do
table.insert(t,"VALUE")
end
jstr = json.encode(t)
v = json.decode(jstr)
--print(json.encode(t))
end
for i = 1,100 do
local t = {}
for j=1,500 do
local m= math.mod(j,3)
if (m==0) then
t['a'..j] = true
elseif m==1 then
t['a'..j] = json.null
else
t['a'..j] = j
end
end
jstr = json.encode(t)
v = json.decode(jstr)
end
print (jstr)
--print(type(t1))
local t2 = os.clock()
print ("Elapsed time=" .. os.difftime(t2,t1) .. "s")

442
libs/json4lua/json/json.lua Executable file
View file

@ -0,0 +1,442 @@
-----------------------------------------------------------------------------
-- JSON4Lua: JSON encoding / decoding support for the Lua language.
-- json Module.
-- Author: Craig Mason-Jones
-- Homepage: http://github.com/craigmj/json4lua/
-- Version: 1.0.1
-- This module is released under the MIT License (MIT).
-- Please see LICENCE.txt for details.
--
-- USAGE:
-- This module exposes two functions:
-- json.encode(o)
-- Returns the table / string / boolean / number / nil / json.null value as a JSON-encoded string.
-- json.decode(json_string)
-- Returns a Lua object populated with the data encoded in the JSON string json_string.
--
-- REQUIREMENTS:
-- compat-5.1 if using Lua 5.0
--
-- CHANGELOG
-- 1.0.1 Introduced set_plugin_info call to register plugin details for Wireshark. Per
-- suggestion by T. Lerman.
-- 0.9.20 Introduction of local Lua functions for private functions (removed _ function prefix).
-- Fixed Lua 5.1 compatibility issues.
-- Introduced json.null to have null values in associative arrays.
-- json.encode() performance improvement (more than 50%) through table.concat rather than ..
-- Introduced decode ability to ignore /**/ comments in the JSON string.
-- 0.9.10 Fix to array encoding / decoding to correctly manage nil/null values in arrays.
-----------------------------------------------------------------------------
-----------------------------------------------------------------------------
-- Imports and dependencies
-----------------------------------------------------------------------------
local math = require('math')
local string = require("string")
local table = require("table")
-----------------------------------------------------------------------------
-- Module declaration
-----------------------------------------------------------------------------
local json = {} -- Public namespace
local json_private = {} -- Private namespace
-- Public constants
json.EMPTY_ARRAY={}
json.EMPTY_OBJECT={}
-- Public functions
-- Private functions
local decode_scanArray
local decode_scanComment
local decode_scanConstant
local decode_scanNumber
local decode_scanObject
local decode_scanString
local decode_scanWhitespace
local encodeString
local isArray
local isEncodable
-----------------------------------------------------------------------------
-- PUBLIC FUNCTIONS
-----------------------------------------------------------------------------
--- Encodes an arbitrary Lua object / variable.
-- @param v The Lua object / variable to be JSON encoded.
-- @return String containing the JSON encoding in internal Lua string format (i.e. not unicode)
function json.encode (v)
-- Handle nil values
if v==nil then
return "null"
end
local vtype = type(v)
-- Handle strings
if vtype=='string' then
return '"' .. json_private.encodeString(v) .. '"' -- Need to handle encoding in string
end
-- Handle booleans
if vtype=='number' or vtype=='boolean' then
return tostring(v)
end
-- Handle tables
if vtype=='table' then
local rval = {}
-- Consider arrays separately
local bArray, maxCount = isArray(v)
if bArray then
for i = 1,maxCount do
table.insert(rval, json.encode(v[i]))
end
else -- An object, not an array
for i,j in pairs(v) do
if isEncodable(i) and isEncodable(j) then
table.insert(rval, '"' .. json_private.encodeString(i) .. '":' .. json.encode(j))
end
end
end
if bArray then
return '[' .. table.concat(rval,',') ..']'
else
return '{' .. table.concat(rval,',') .. '}'
end
end
-- Handle null values
if vtype=='function' and v==json.null then
return 'null'
end
assert(false,'encode attempt to encode unsupported type ' .. vtype .. ':' .. tostring(v))
end
--- Decodes a JSON string and returns the decoded value as a Lua data structure / value.
-- @param s The string to scan.
-- @param [startPos] Optional starting position where the JSON string is located. Defaults to 1.
-- @param Lua object, number The object that was scanned, as a Lua table / string / number / boolean or nil,
-- and the position of the first character after
-- the scanned JSON object.
function json.decode(s, startPos)
startPos = startPos and startPos or 1
startPos = decode_scanWhitespace(s,startPos)
assert(startPos<=string.len(s), 'Unterminated JSON encoded object found at position in [' .. s .. ']')
local curChar = string.sub(s,startPos,startPos)
-- Object
if curChar=='{' then
return decode_scanObject(s,startPos)
end
-- Array
if curChar=='[' then
return decode_scanArray(s,startPos)
end
-- Number
if string.find("+-0123456789.e", curChar, 1, true) then
return decode_scanNumber(s,startPos)
end
-- String
if curChar==[["]] or curChar==[[']] then
return decode_scanString(s,startPos)
end
if string.sub(s,startPos,startPos+1)=='/*' then
return json.decode(s, decode_scanComment(s,startPos))
end
-- Otherwise, it must be a constant
return decode_scanConstant(s,startPos)
end
--- The null function allows one to specify a null value in an associative array (which is otherwise
-- discarded if you set the value with 'nil' in Lua. Simply set t = { first=json.null }
function json.null()
return json.null -- so json.null() will also return null ;-)
end
-----------------------------------------------------------------------------
-- Internal, PRIVATE functions.
-- Following a Python-like convention, I have prefixed all these 'PRIVATE'
-- functions with an underscore.
-----------------------------------------------------------------------------
--- Scans an array from JSON into a Lua object
-- startPos begins at the start of the array.
-- Returns the array and the next starting position
-- @param s The string being scanned.
-- @param startPos The starting position for the scan.
-- @return table, int The scanned array as a table, and the position of the next character to scan.
function decode_scanArray(s,startPos)
local array = {} -- The return value
local stringLen = string.len(s)
assert(string.sub(s,startPos,startPos)=='[','decode_scanArray called but array does not start at position ' .. startPos .. ' in string:\n'..s )
startPos = startPos + 1
-- Infinite loop for array elements
local index = 1
repeat
startPos = decode_scanWhitespace(s,startPos)
assert(startPos<=stringLen,'JSON String ended unexpectedly scanning array.')
local curChar = string.sub(s,startPos,startPos)
if (curChar==']') then
return array, startPos+1
end
if (curChar==',') then
startPos = decode_scanWhitespace(s,startPos+1)
end
assert(startPos<=stringLen, 'JSON String ended unexpectedly scanning array.')
object, startPos = json.decode(s,startPos)
array[index] = object
index = index + 1
until false
end
--- Scans a comment and discards the comment.
-- Returns the position of the next character following the comment.
-- @param string s The JSON string to scan.
-- @param int startPos The starting position of the comment
function decode_scanComment(s, startPos)
assert( string.sub(s,startPos,startPos+1)=='/*', "decode_scanComment called but comment does not start at position " .. startPos)
local endPos = string.find(s,'*/',startPos+2)
assert(endPos~=nil, "Unterminated comment in string at " .. startPos)
return endPos+2
end
--- Scans for given constants: true, false or null
-- Returns the appropriate Lua type, and the position of the next character to read.
-- @param s The string being scanned.
-- @param startPos The position in the string at which to start scanning.
-- @return object, int The object (true, false or nil) and the position at which the next character should be
-- scanned.
function decode_scanConstant(s, startPos)
local consts = { ["true"] = true, ["false"] = false, ["null"] = nil }
local constNames = {"true","false","null"}
for i,k in pairs(constNames) do
if string.sub(s,startPos, startPos + string.len(k) -1 )==k then
return consts[k], startPos + string.len(k)
end
end
assert(nil, 'Failed to scan constant from string ' .. s .. ' at starting position ' .. startPos)
end
--- Scans a number from the JSON encoded string.
-- (in fact, also is able to scan numeric +- eqns, which is not
-- in the JSON spec.)
-- Returns the number, and the position of the next character
-- after the number.
-- @param s The string being scanned.
-- @param startPos The position at which to start scanning.
-- @return number, int The extracted number and the position of the next character to scan.
function decode_scanNumber(s,startPos)
local endPos = startPos+1
local stringLen = string.len(s)
local acceptableChars = "+-0123456789.e"
while (string.find(acceptableChars, string.sub(s,endPos,endPos), 1, true)
and endPos<=stringLen
) do
endPos = endPos + 1
end
local stringValue = 'return ' .. string.sub(s,startPos, endPos-1)
local stringEval = load(stringValue)
assert(stringEval, 'Failed to scan number [ ' .. stringValue .. '] in JSON string at position ' .. startPos .. ' : ' .. endPos)
return stringEval(), endPos
end
--- Scans a JSON object into a Lua object.
-- startPos begins at the start of the object.
-- Returns the object and the next starting position.
-- @param s The string being scanned.
-- @param startPos The starting position of the scan.
-- @return table, int The scanned object as a table and the position of the next character to scan.
function decode_scanObject(s,startPos)
local object = {}
local stringLen = string.len(s)
local key, value
assert(string.sub(s,startPos,startPos)=='{','decode_scanObject called but object does not start at position ' .. startPos .. ' in string:\n' .. s)
startPos = startPos + 1
repeat
startPos = decode_scanWhitespace(s,startPos)
assert(startPos<=stringLen, 'JSON string ended unexpectedly while scanning object.')
local curChar = string.sub(s,startPos,startPos)
if (curChar=='}') then
return object,startPos+1
end
if (curChar==',') then
startPos = decode_scanWhitespace(s,startPos+1)
end
assert(startPos<=stringLen, 'JSON string ended unexpectedly scanning object.')
-- Scan the key
key, startPos = json.decode(s,startPos)
assert(startPos<=stringLen, 'JSON string ended unexpectedly searching for value of key ' .. key)
startPos = decode_scanWhitespace(s,startPos)
assert(startPos<=stringLen, 'JSON string ended unexpectedly searching for value of key ' .. key)
assert(string.sub(s,startPos,startPos)==':','JSON object key-value assignment mal-formed at ' .. startPos)
startPos = decode_scanWhitespace(s,startPos+1)
assert(startPos<=stringLen, 'JSON string ended unexpectedly searching for value of key ' .. key)
value, startPos = json.decode(s,startPos)
object[key]=value
until false -- infinite loop while key-value pairs are found
end
-- START SoniEx2
-- Initialize some things used by decode_scanString
-- You know, for efficiency
local escapeSequences = {
["\\t"] = "\t",
["\\f"] = "\f",
["\\r"] = "\r",
["\\n"] = "\n",
["\\b"] = "\b"
}
setmetatable(escapeSequences, {__index = function(t,k)
-- skip "\" aka strip escape
return string.sub(k,2)
end})
-- END SoniEx2
--- Scans a JSON string from the opening inverted comma or single quote to the
-- end of the string.
-- Returns the string extracted as a Lua string,
-- and the position of the next non-string character
-- (after the closing inverted comma or single quote).
-- @param s The string being scanned.
-- @param startPos The starting position of the scan.
-- @return string, int The extracted string as a Lua string, and the next character to parse.
function decode_scanString(s,startPos)
assert(startPos, 'decode_scanString(..) called without start position')
local startChar = string.sub(s,startPos,startPos)
-- START SoniEx2
-- PS: I don't think single quotes are valid JSON
assert(startChar == [["]] or startChar == [[']],'decode_scanString called for a non-string')
--assert(startPos, "String decoding failed: missing closing " .. startChar .. " for string at position " .. oldStart)
local t = {}
local i,j = startPos,startPos
while string.find(s, startChar, j+1) ~= j+1 do
local oldj = j
i,j = string.find(s, "\\.", j+1)
local x,y = string.find(s, startChar, oldj+1)
if not i or x < i then
i,j = x,y-1
end
table.insert(t, string.sub(s, oldj+1, i-1))
if string.sub(s, i, j) == "\\u" then
local a = string.sub(s,j+1,j+4)
j = j + 4
local n = tonumber(a, 16)
assert(n, "String decoding failed: bad Unicode escape " .. a .. " at position " .. i .. " : " .. j)
-- math.floor(x/2^y) == lazy right shift
-- a % 2^b == bitwise_and(a, (2^b)-1)
-- 64 = 2^6
-- 4096 = 2^12 (or 2^6 * 2^6)
local x
if n < 0x80 then
x = string.char(n % 0x80)
elseif n < 0x800 then
-- [110x xxxx] [10xx xxxx]
x = string.char(0xC0 + (math.floor(n/64) % 0x20), 0x80 + (n % 0x40))
else
-- [1110 xxxx] [10xx xxxx] [10xx xxxx]
x = string.char(0xE0 + (math.floor(n/4096) % 0x10), 0x80 + (math.floor(n/64) % 0x40), 0x80 + (n % 0x40))
end
table.insert(t, x)
else
table.insert(t, escapeSequences[string.sub(s, i, j)])
end
end
table.insert(t,string.sub(j, j+1))
assert(string.find(s, startChar, j+1), "String decoding failed: missing closing " .. startChar .. " at position " .. j .. "(for string at position " .. startPos .. ")")
return table.concat(t,""), j+2
-- END SoniEx2
end
--- Scans a JSON string skipping all whitespace from the current start position.
-- Returns the position of the first non-whitespace character, or nil if the whole end of string is reached.
-- @param s The string being scanned
-- @param startPos The starting position where we should begin removing whitespace.
-- @return int The first position where non-whitespace was encountered, or string.len(s)+1 if the end of string
-- was reached.
function decode_scanWhitespace(s,startPos)
local whitespace=" \n\r\t"
local stringLen = string.len(s)
while ( string.find(whitespace, string.sub(s,startPos,startPos), 1, true) and startPos <= stringLen) do
startPos = startPos + 1
end
return startPos
end
--- Encodes a string to be JSON-compatible.
-- This just involves back-quoting inverted commas, back-quotes and newlines, I think ;-)
-- @param s The string to return as a JSON encoded (i.e. backquoted string)
-- @return The string appropriately escaped.
local escapeList = {
['"'] = '\\"',
['\\'] = '\\\\',
['/'] = '\\/',
['\b'] = '\\b',
['\f'] = '\\f',
['\n'] = '\\n',
['\r'] = '\\r',
['\t'] = '\\t'
}
function json_private.encodeString(s)
local s = tostring(s)
return s:gsub(".", function(c) return escapeList[c] end) -- SoniEx2: 5.0 compat
end
-- Determines whether the given Lua type is an array or a table / dictionary.
-- We consider any table an array if it has indexes 1..n for its n items, and no
-- other data in the table.
-- I think this method is currently a little 'flaky', but can't think of a good way around it yet...
-- @param t The table to evaluate as an array
-- @return boolean, number True if the table can be represented as an array, false otherwise. If true,
-- the second returned value is the maximum
-- number of indexed elements in the array.
function isArray(t)
-- Next we count all the elements, ensuring that any non-indexed elements are not-encodable
-- (with the possible exception of 'n')
if (t == json.EMPTY_ARRAY) then return true, 0 end
if (t == json.EMPTY_OBJECT) then return false end
local maxIndex = 0
for k,v in pairs(t) do
if (type(k)=='number' and math.floor(k)==k and 1<=k) then -- k,v is an indexed pair
if (not isEncodable(v)) then return false end -- All array elements must be encodable
maxIndex = math.max(maxIndex,k)
else
if (k=='n') then
if v ~= (t.n or #t) then return false end -- False if n does not hold the number of elements
else -- Else of (k=='n')
if isEncodable(v) then return false end
end -- End of (k~='n')
end -- End of k,v not an indexed pair
end -- End of loop across all pairs
return true, maxIndex
end
--- Determines whether the given Lua object / table / variable can be JSON encoded. The only
-- types that are JSON encodable are: string, boolean, number, nil, table and json.null.
-- In this implementation, all other types are ignored.
-- @param o The object to examine.
-- @return boolean True if the object should be JSON encoded, false if it should be ignored.
function isEncodable(o)
local t = type(o)
return (t=='string' or t=='boolean' or t=='number' or t=='nil' or t=='table') or
(t=='function' and o==json.null)
end
-----------------------------------------------------------------------------
-- Display version information for Wireshark
-----------------------------------------------------------------------------
if set_plugin_info~=nil then
local plugin_info = {
version = "1.0.1",
author = "Craig Mason-Jones",
repository = "https://github.com/craigmj/json4lua"
}
set_plugin_info(plugin_info)
end
return json

107
libs/json4lua/json/rpc.lua Executable file
View file

@ -0,0 +1,107 @@
-----------------------------------------------------------------------------
-- JSONRPC4Lua: JSON RPC client calls over http for the Lua language.
-- json.rpc Module.
-- Author: Craig Mason-Jones
-- Homepage: http://github.com/craigmj/json4lua/
-- Version: 1.0.0
-- This module is released under the MIT License (MIT).
-- Please see LICENCE.txt for details.
--
-- USAGE:
-- This module exposes two functions:
-- proxy( 'url')
-- Returns a proxy object for calling the JSON RPC Service at the given url.
-- call ( 'url', 'method', ...)
-- Calls the JSON RPC server at the given url, invokes the appropriate method, and
-- passes the remaining parameters. Returns the result and the error. If the result is nil, an error
-- should be there (or the system returned a null). If an error is there, the result should be nil.
--
-- REQUIREMENTS:
-- Lua socket 2.0 (http://www.cs.princeton.edu/~diego/professional/luasocket/)
-- json (The JSON4Lua package with which it is bundled)
-- compat-5.1 if using Lua 5.0.
-----------------------------------------------------------------------------
local json = require('json')
json.rpc = {} -- Module public namespace
-----------------------------------------------------------------------------
-- Imports and dependencies
-----------------------------------------------------------------------------
local json = require('json')
local http = require("socket.http")
-----------------------------------------------------------------------------
-- PUBLIC functions
-----------------------------------------------------------------------------
--- Creates an RPC Proxy object for the given Url of a JSON-RPC server.
-- @param url The URL for the JSON RPC Server.
-- @return Object on which JSON-RPC remote methods can be called.
-- EXAMPLE Usage:
-- local jsolait = json.rpc.proxy('http://jsolait.net/testj.py')
-- print(jsolait.echo('This is a test of the echo method!'))
-- print(jsolait.args2String('first','second','third'))
-- table.foreachi( jsolait.args2Array(5,4,3,2,1), print)
function json.rpc.proxy(url)
local serverProxy = {}
local proxyMeta = {
__index = function(self, key)
return function(...)
return json.rpc.call(url, key, ...)
end
end
}
setmetatable(serverProxy, proxyMeta)
return serverProxy
end
--- Calls a JSON RPC method on a remote server.
-- Returns a boolean true if the call succeeded, false otherwise.
-- On success, the second returned parameter is the decoded
-- JSON object from the server.
-- On http failure, returns nil and an error message.
-- On success, returns the result and nil.
-- @param url The url of the JSON RPC server.
-- @param method The method being called.
-- @param ... Parameters to pass to the method.
-- @return result, error The JSON RPC result and error. One or the other should be nil. If both
-- are nil, this means that the result of the RPC call was nil.
-- EXAMPLE Usage:
-- print(json.rpc.call('http://jsolait.net/testj.py','echo','This string will be returned'))
function json.rpc.call(url, method, ...)
local JSONRequestArray = {
id=tostring(math.random()),
["method"]=method,
["jsonrpc"]="2.0",
params = ...
}
local httpResponse, result , code
local jsonRequest = json.encode(JSONRequestArray)
-- We use the sophisticated http.request form (with ltn12 sources and sinks) so that
-- we can set the content-type to text/plain. While this shouldn't strictly-speaking be true,
-- it seems a good idea (Xavante won't work w/out a content-type header, although a patch
-- is needed to Xavante to make it work with text/plain)
local ltn12 = require('ltn12')
local resultChunks = {}
httpResponse, code = http.request(
{ ['url'] = url,
sink = ltn12.sink.table(resultChunks),
method = 'POST',
headers = { ['content-type']='application/json-rpc', ['content-length']=string.len(jsonRequest) },
source = ltn12.source.string(jsonRequest)
}
)
httpResponse = table.concat(resultChunks)
-- Check the http response code
if (code~=200) then
return nil, "HTTP ERROR: " .. code
end
-- And decode the httpResponse and check the JSON RPC result code
result = json.decode( httpResponse )
if result.result then
return result.result, nil
else
return nil, result.error
end
end

View file

@ -0,0 +1,78 @@
-----------------------------------------------------------------------------
-- JSONRPC4Lua: JSON RPC server for exposing Lua objects as JSON RPC callable
-- objects via http.
-- json.rpcserver Module.
-- Author: Craig Mason-Jones
-- Homepage: http://github.com/craigmj/json4lua/
-- Version: 1.0.0
-- This module is released under the MIT License (MIT).
-- Please see LICENCE.txt for details.
--
-- USAGE:
-- This module exposes one function:
-- server(luaClass, packReturn)
-- Manages incoming JSON RPC request forwarding the method call to the given
-- object. If packReturn is true, multiple return values are packed into an
-- array on return.
--
-- IMPORTANT NOTES:
-- 1. This version ought really not be 0.9.10, since this particular part of the
-- JSONRPC4Lua package is very first-draft. However, the JSON4Lua package with which
-- it comes is quite solid, so there you have it :-)
-- 2. This has only been tested with Xavante webserver, with which it works
-- if you patch CGILua to accept 'text/plain' content type. See doc\cgilua_patch.html
-- for details.
----------------------------------------------------------------------------
module ('json.rpcserver')
---
-- Implements a JSON RPC Server wrapping for luaClass, exposing each of luaClass's
-- methods as JSON RPC callable methods.
-- @param luaClass The JSON RPC class to expose.
-- @param packReturn If true, the server will automatically wrap any
-- multiple-value returns into an array. Single returns remain single returns. If
-- false, when a function returns multiple values, only the first of these values will
-- be returned.
--
function serve(luaClass, packReturn)
cgilua.contentheader('text','plain')
require('cgilua')
require ('json')
local postData = ""
if not cgilua.servervariable('CONTENT_LENGTH') then
cgilua.put("Please access JSON Request using HTTP POST Request")
return 0
else
postData = cgi[1] -- SAPI.Request.getpostdata() --[[{ "id":1, "method":"echo","params":["Hi there"]}]] --
end
-- @TODO Catch an error condition on decoding the data
local jsonRequest = json.decode(postData)
local jsonResponse = {}
jsonResponse.id = jsonRequest.id
local method = luaClass[ jsonRequest.method ]
if not method then
jsonResponse.error = 'Method ' .. jsonRequest.method .. ' does not exist at this server.'
else
local callResult = { pcall( method, unpack( jsonRequest.params ) ) }
if callResult[1] then -- Function call successfull
table.remove(callResult,1)
if packReturn and table.getn(callResult)>1 then
jsonResponse.result = callResult
else
jsonResponse.result = unpack(callResult) -- NB: Does not support multiple argument returns
end
else
jsonResponse.error = callResult[2]
end
end
-- Output the result
-- TODO: How to be sure that the result and error tags are there even when they are nil in Lua?
-- Can force them by hand... ?
cgilua.contentheader('text','plain')
cgilua.put( json.encode( jsonResponse ) )
end

View file

@ -0,0 +1,32 @@
package="JSON4Lua"
version="1.0.0"
source = {
url = "git://github.com/craigmj/json4lua.git",
tag = "1.0.0"
}
description = {
summary = "JSON4Lua and JSONRPC4Lua implement JSON (JavaScript Object Notation) encoding and decoding and a JSON-RPC-over-http client for Lua.",
detailed = [[
JSON4Lua and JSONRPC4Lua implement JSON (JavaScript Object Notation)
encoding and decoding and a JSON-RPC-over-http client for Lua.
JSON is JavaScript Object Notation, a simple encoding of
Javascript-like objects that is ideal for lightweight transmission
of relatively weakly-typed data. A sub-package of JSON4Lua is
JSONRPC4Lua, which provides a simple JSON-RPC-over-http client and server
(in a CGILua environment) for Lua.
]],
homepage = "http://github.com/craigmj/json4lua/",
license = "GPL"
}
dependencies = {
"lua >= 5.2",
"luasocket",
}
build = {
type = "builtin",
modules = {
["json"] = "json/json.lua",
["json.rpc"] = "json/rpc.lua"
}
}