├── README.md
├── Scripts
└── UOJS
│ └── UOJS
│ ├── AssemblyInfo.cs
│ ├── GameProxy.cs
│ ├── LitJson
│ ├── IJsonWrapper.cs
│ ├── JsonData.cs
│ ├── JsonException.cs
│ ├── JsonMapper.cs
│ ├── JsonMockWrapper.cs
│ ├── JsonReader.cs
│ ├── JsonWriter.cs
│ ├── Lexer.cs
│ └── ParserToken.cs
│ ├── UOJS.cs
│ ├── Ultima.dll
│ ├── WebSocketClient.cs
│ ├── WebSocketPacket.cs
│ └── bin
│ └── Debug
│ └── Ultima.dll
├── Ultima.dll
└── WebClient
├── index.html
├── jquery.min.js
├── uo.js
└── uo2.js
/README.md:
--------------------------------------------------------------------------------
1 | Notice
2 | ==========
3 |
4 | Hey!
5 |
6 | I've restarted this project and made it 62% less shitty! Check it out here: https://github.com/kevinhikaruevans/uojs2
7 |
8 | Overview
9 | ==========
10 |
11 | uojs is a proof-of-concept piece for a port of Ultima Online for HTML5 web browsers. This project was created for myself to learn more about the cool features of Javascript. It utilizes both HTML5's WebSockets and Canvas. It is completely integrated into RunUO and uses reflection to access UltimaSDK.
12 |
13 | Installation
14 | ==========
15 |
16 | It is completely plug & play.
17 |
18 | The file layout should be something like:
19 | - / - Root directory (containing RunUO.exe)
20 | - /WebClient
21 | - jquery.min.js
22 | - index.html
23 | - uo.js
24 | - /Scripts
25 | - /UOJS
26 | - /LitJson
27 | - ...
28 | - GameProxy.cs
29 | - UOJS.cs
30 | - WebSocketClient.cs
31 | - WebSocketPacket.cs
32 | - Ultima.dll
33 |
34 | Dependencies
35 | ==========
36 |
37 | uojs depends on the following:
38 | - jQuery 1.8+
39 | - LitJSON 0.7.0+
40 | - UltimaSDK
41 |
42 | Compatibility
43 | ==========
44 |
45 | This project should run on all RunUO versions (hopefully). It is tested on Mono 2.10.8.1 on Debian.
46 |
47 | The web browsers used _must_ support both WebSockets and the Canvas element. Luckily, all newer web browsers support this.
48 |
49 | Usage
50 | ==========
51 |
52 | The default port is 2580.
53 | Accessing the client should be easy. You can access it by opening a web browser on `http://localhost:2580/WebClient/index.html`
54 |
55 | There should be a caching proxy or even a CDN for the files/art that cache based on the URI. Doing so will prevent heavy load on the server. Nginx, Lighttpd, Apache will all do this fairly easily.
56 | Everything must either be cached or not cached. You cannot only cache certain files and not cache others (it will not run if it is). The only URI that cannot be cached is /game, since it is the WebSocket stream.
57 |
58 | Screenshots
59 | ==========
60 |
61 | * [Chat works... I guess](http://i.imgur.com/Bxm89KY.png) (3/05/13)
62 | * [Partial mobile implementation](http://i.imgur.com/hRRE42k.jpg) under Firefox 19 (2/21/13)
63 | * [Another screenshot](http://i.imgur.com/jLBPmRE.png) making use of the new [semi-broken] renderer (newer! 2/19/13)
64 | * [A screenshot](http://i.imgur.com/VClu5.png) (using the old map renderer)
65 |
--------------------------------------------------------------------------------
/Scripts/UOJS/UOJS/AssemblyInfo.cs:
--------------------------------------------------------------------------------
1 | using System.Reflection;
2 | using System.Runtime.CompilerServices;
3 |
4 | // Information about this assembly is defined by the following attributes.
5 | // Change them to the values specific to your project.
6 |
7 | [assembly: AssemblyTitle("UOJS")]
8 | [assembly: AssemblyDescription("")]
9 | [assembly: AssemblyConfiguration("")]
10 | [assembly: AssemblyCompany("")]
11 | [assembly: AssemblyProduct("")]
12 | [assembly: AssemblyCopyright("kevin")]
13 | [assembly: AssemblyTrademark("")]
14 | [assembly: AssemblyCulture("")]
15 |
16 | // The assembly version has the format "{Major}.{Minor}.{Build}.{Revision}".
17 | // The form "{Major}.{Minor}.*" will automatically update the build and revision,
18 | // and "{Major}.{Minor}.{Build}.*" will update just the revision.
19 |
20 | [assembly: AssemblyVersion("1.0.*")]
21 |
22 | // The following attributes are used to specify the signing key for the assembly,
23 | // if desired. See the Mono documentation for more information about signing.
24 |
25 | //[assembly: AssemblyDelaySign(false)]
26 | //[assembly: AssemblyKeyFile("")]
27 |
28 |
--------------------------------------------------------------------------------
/Scripts/UOJS/UOJS/GameProxy.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using UOJS;
3 | using System.Net.Sockets;
4 | using System.Net;
5 | using System.Threading;
6 | using System.Security.Cryptography;
7 | using System.Text;
8 | using System.Collections.Generic;
9 | using System.Collections.Specialized;
10 | using System.Drawing;
11 | using System.IO;
12 | using System.Text.RegularExpressions;
13 | using System.Runtime.InteropServices;
14 | using System.Reflection;
15 |
16 | namespace UOJS.Network
17 | {
18 | ///
19 | /// A class containing the WebSocket proxy layer
20 | ///
21 | public class GameProxy
22 | {
23 | ///
24 | /// The port the proxy & server should listen on (NOT THE UO SOCKET PORT!).
25 | ///
26 | private static readonly int ListeningPort = 2580;
27 |
28 | ///
29 | /// The directory containing the HTML & JS files.
30 | ///
31 | private static readonly string WebDirectory = "WebClient";
32 |
33 | ///
34 | /// If you have a lot of memory, set this to true. If not, use your webserver or cdn to cache these in a reverse proxy.
35 | ///
36 | private static readonly bool CacheBitmaps = false;
37 |
38 | private static readonly string UltimaDllLocation = "./Ultima.dll";
39 |
40 | private static readonly string MagicKey = "258EAFA5-E914-47DA-95CA-C5AB0DC85B11";
41 |
42 |
43 | ///
44 | /// Initialize this instance.
45 | ///
46 | public static void Initialize ()
47 | {
48 | if (!File.Exists (UltimaDllLocation)) {
49 | UOJS.Log ("Error: Cannot find Ultima.dll");
50 | return;
51 | }
52 | if (WebDirectory.Length <= 0 || !InitializeFiles ()) {
53 | UOJS.Log ("Error: WebDirectory (\"{0}\") does not exist.", WebDirectory);
54 | return;
55 | }
56 |
57 | m_Ultima = Assembly.LoadFrom (UltimaDllLocation);
58 | m_SHA1 = SHA1.Create ();
59 |
60 | UOJS.Log ("Starting UOJS (version {0}, Ultima version {1}, port {2})", UOJS.Version, System.Diagnostics.FileVersionInfo.GetVersionInfo (m_Ultima.Location).FileVersion, ListeningPort);
61 | GameProxy.BeginListening ();
62 | }
63 |
64 | private static Assembly m_Ultima;
65 | private static Socket m_ListeningSocket;
66 | private static bool m_Listening;
67 | private static Thread m_Thread;
68 | private static ManualResetEvent m_AcceptEvent;
69 | private static SHA1 m_SHA1;
70 | private static DateTime m_StartDate;
71 | private static Encoding m_Encoding = Encoding.UTF8;
72 | private static FileSystemWatcher m_FileSystemWatcher;
73 | private static Dictionary m_RawFiles;
74 |
75 | public enum RequestType
76 | {
77 | GameRequest = 'G',
78 | WebRequest = 'W',
79 | None = 0
80 | }
81 |
82 | ///
83 | /// Begins listening on a new thread.
84 | ///
85 | public static void BeginListening ()
86 | {
87 | m_StartDate = DateTime.UtcNow;
88 | m_Widths = new Dictionary ();
89 | m_Listening = true;
90 | m_Thread = new Thread (Listen);
91 | m_Thread.Name = "GameProxyListener"; // for debugging
92 | m_Thread.Start ();
93 | }
94 |
95 | #region File Handling
96 | public static bool InitializeFiles ()
97 | {
98 | if (!Directory.Exists (WebDirectory))
99 | return false;
100 | m_RawFiles = new Dictionary ();
101 | m_FileSystemWatcher = new FileSystemWatcher (WebDirectory);
102 | m_FileSystemWatcher.EnableRaisingEvents = true;
103 | m_FileSystemWatcher.Path = WebDirectory;
104 | m_FileSystemWatcher.Filter = "*.*";
105 | m_FileSystemWatcher.Created += HandleFileSystemChange;
106 | m_FileSystemWatcher.Changed += HandleFileSystemChange;
107 | m_FileSystemWatcher.Deleted += HandleFileSystemChange;
108 |
109 | foreach (string fileName in Directory.GetFiles(WebDirectory))
110 | LoadFile (fileName);
111 | return true;
112 | }
113 |
114 | protected static void LoadFile (string fileName)
115 | {
116 | Console.WriteLine ("File Load {0}", fileName);
117 | if (fileName.StartsWith ("."))
118 | return;
119 | using (StreamReader reader = new StreamReader(fileName, m_Encoding)) {
120 | if (m_RawFiles.ContainsKey (fileName.Replace ("\\", "/")))
121 | m_RawFiles [fileName.Replace ("\\", "/")] = reader.ReadToEnd ();
122 | else
123 | m_RawFiles.Add (fileName.Replace ("\\", "/"), reader.ReadToEnd ());
124 | reader.Close ();
125 | }
126 | }
127 | protected static void HandleFileSystemChange (object sender, FileSystemEventArgs e)
128 | {
129 | LoadFile (e.FullPath);
130 | }
131 | #endregion
132 |
133 | ///
134 | /// Begins listening.
135 | ///
136 | protected static void Listen ()
137 | {
138 | m_ListeningSocket = new Socket (AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
139 | m_ListeningSocket.Bind (new IPEndPoint (IPAddress.Loopback, ListeningPort));
140 | m_ListeningSocket.LingerState.Enabled = true;
141 | m_ListeningSocket.Listen (8);
142 | m_AcceptEvent = new ManualResetEvent (false);
143 |
144 | UOJS.Log ("Listening: {0}", m_ListeningSocket.LocalEndPoint);
145 |
146 | while (m_Listening) {
147 | m_AcceptEvent.Reset ();
148 |
149 | m_ListeningSocket.BeginAccept (new AsyncCallback (AcceptCallback), m_ListeningSocket);
150 | m_AcceptEvent.WaitOne ();
151 | }
152 | UOJS.Log ("Goodbye.");
153 | }
154 |
155 | public static void AcceptCallback (IAsyncResult ar)
156 | {
157 | m_AcceptEvent.Set ();
158 |
159 | Socket webSocket = m_ListeningSocket.EndAccept (ar);
160 | WebSocketClient client = new WebSocketClient (webSocket);
161 |
162 | UOJS.Log ("Client [{0}]: Connection Detected", client.WebSocket.RemoteEndPoint);
163 | webSocket.BeginReceive (client.WriteBuffer, 0, client.WriteBuffer.Length, SocketFlags.None, new AsyncCallback (ReadCallback), client);
164 | }
165 |
166 | ///
167 | /// Creates the HTTP headers.
168 | ///
169 | /// The type of header.
170 | /// The full headers read.
171 | /// The headers being sent.
172 | /// The shortened URI.
173 | /// The full URI.
174 | public static RequestType CreateHeaders (string header, out string sendHeaders, out string shortUri, out string fullUri)
175 | {
176 | string[] headers = header.Split (new char[] { '\r', '\n' }, StringSplitOptions.RemoveEmptyEntries);
177 | string[] first = headers [0].Split (' ');
178 | string method = first [0];
179 | fullUri = first [1];
180 | shortUri = fullUri.Substring (0, fullUri.IndexOf ('?') == -1 ? fullUri.Length : fullUri.IndexOf ('?'));
181 |
182 | // For 301: /WebClient -> /WebClient/index.html
183 | if (shortUri == "/" + WebDirectory) {
184 | sendHeaders = string.Format ("HTTP/1.1 301 Moved Permanently{0}"
185 | + "Location: /{1}/index.html{0}"
186 | + "Content-Type: text/html{0}{0}301 Moved", "\r\n", WebDirectory);
187 | return RequestType.WebRequest;
188 | }
189 |
190 | switch (shortUri) {
191 | default:
192 | {
193 | if (m_RawFiles.ContainsKey (shortUri.Substring (1))) {
194 | string mime = (shortUri.EndsWith ("html") ? "html" : (shortUri.EndsWith ("js") ? "javascript" : "plain"));
195 |
196 | sendHeaders = string.Format ("HTTP/1.1 200 OK{0}"
197 | + "Content-Type: text/{2}{0}"
198 | + "Connection: close{0}{0}{1}", "\r\n", m_RawFiles [shortUri.Substring (1)], mime);
199 |
200 | } else {
201 | sendHeaders = string.Format ("HTTP/1.1 200 OK{0}"
202 | + "Content-Type: text/html{0}"
203 | + "Connection: close{0}{0}Hello.
This server is running UOJS, Version {1}. The server time is {2}. This is {3}",
204 | "\r\n",
205 | UOJS.Version,
206 | DateTime.Now,
207 | shortUri);
208 | foreach (string k in m_RawFiles.Keys)
209 | sendHeaders += k + " ";
210 | }
211 | return RequestType.WebRequest;
212 | }
213 |
214 | case "favicon.png":
215 | case "favicon.ico":
216 | {
217 | sendHeaders = string.Format ("HTTP/1.1 404 Not Found {0}"
218 | + "Content-Type: text/html{0}"
219 | + "Connection: close{0}{0}", "\r\n");
220 | return RequestType.WebRequest;
221 | }
222 | case "/getcliloc":
223 | case "/getaniminfo":
224 | case "/getmapinfo":
225 | case "/td":
226 | {
227 | string orgin = null, host = null;
228 |
229 | foreach (string h in headers) {
230 | string[] parts = h.Split (new char[] { ' ' }, 2);
231 | switch (parts [0]) {
232 | case "Orgin:":
233 | {
234 | orgin = parts [1];
235 | break;
236 | }
237 | case "Host:":
238 | {
239 | host = parts [1];
240 | break;
241 | }
242 | }
243 | }
244 | sendHeaders = string.Format ("HTTP/1.1 200 OK{0}"
245 | + "Content-Type: application/javascript{0}"
246 | + "Access-Control-Allow-Origin: *{0}"
247 | + "Connection: close{0}{0}", "\r\n");
248 |
249 | return RequestType.WebRequest;
250 | }
251 |
252 | case "/getgump":
253 | case "/getobj":
254 | case "/getanim":
255 | {
256 | sendHeaders = string.Format ("HTTP/1.1 200 OK{0}"
257 | + "Content-Type: image/png{0}"
258 | + "Cache-Control: public, max-age=1209600{0}"
259 | + "Access-control-allow-origin: *{0}"
260 | + "Access-control-allow-credentials: true{0}"
261 | + "Expires: {1}{0}"
262 | + "Last-Modified: {2}{0}"
263 | + "Connection: close{0}{0}", "\r\n", (DateTime.Now + TimeSpan.FromDays (14)).ToString ("r"), m_StartDate.ToString ("r"));
264 | return RequestType.WebRequest;
265 | }
266 |
267 | case "/game":
268 | {
269 | if (m_SHA1 == null)
270 | m_SHA1 = SHA1.Create ();
271 | string auth = null, orgin = null, host = null;
272 |
273 | foreach (string h in headers) {
274 | string[] parts = h.Split (new char[] { ' ' }, 2);
275 | switch (parts [0]) {
276 | case "Sec-WebSocket-Key:":
277 | {
278 | auth = Convert.ToBase64String (m_SHA1.ComputeHash (Encoding.UTF8.GetBytes (parts [1] + MagicKey)));
279 | break;
280 | }
281 | case "Orgin:":
282 | {
283 | orgin = parts [1];
284 | break;
285 | }
286 | case "Host:":
287 | {
288 | host = parts [1];
289 | break;
290 | }
291 | }
292 | }
293 | sendHeaders = string.Format ("HTTP/1.1 101 Switching Protocols{0}"
294 | + "Upgrade: WebSocket{0}"
295 | + "Connection: Upgrade{0}"
296 | + "Sec-WebSocket-Accept: {1}{0}"
297 | + "WebSocket-Protocol: 13{0}"
298 | + "Orgin: {2}{0}"
299 | + "WebSocket-Location: ws://{3}/{4}{0}{0}", "\r\n", auth, orgin == null ? "http://127.0.0.1" : orgin, host, fullUri.Replace ("/", ""));
300 |
301 | return RequestType.GameRequest;
302 | }
303 | }
304 | }
305 |
306 | public static void ReadCallback (IAsyncResult ar)
307 | {
308 | WebSocketClient client = (WebSocketClient)ar.AsyncState;
309 | Socket webSocket = client.WebSocket;
310 | int read;
311 | try {
312 | read = webSocket.Connected ? webSocket.EndReceive (ar) : 0;
313 | } catch (Exception e) {
314 | read = 0;
315 | Console.WriteLine ("Socket [disposed]: {0}", e.Message);
316 | }
317 | if (read > 0) {
318 | if (!client.SentHeaders) {
319 | string sendHeaders, shortUri, fullUri;
320 | RequestType type = CreateHeaders (m_Encoding.GetString (client.WriteBuffer),
321 | out sendHeaders,
322 | out shortUri,
323 | out fullUri);
324 |
325 | switch (type) {
326 | case RequestType.GameRequest:
327 | {
328 | client.WebSocket.BeginSend (ASCIIEncoding.ASCII.GetBytes (sendHeaders), 0, sendHeaders.Length, SocketFlags.None, new AsyncCallback (SendCallback), client);
329 | Console.WriteLine ("Client [{0}]: Handshake OK", client.WebSocket.RemoteEndPoint);
330 | break;
331 | }
332 | case RequestType.WebRequest:
333 | {
334 | Console.WriteLine ("WebReq [{0}]: Parsed", client.WebSocket.RemoteEndPoint);
335 | byte[] toSend = ParseWebRequest (client, shortUri, fullUri);
336 | byte[] headers = ASCIIEncoding.ASCII.GetBytes (sendHeaders);
337 | byte[] all = new byte[headers.Length + toSend.Length];
338 |
339 | Array.Copy (headers, all, headers.Length);
340 | Array.Copy (toSend, 0, all, headers.Length, toSend.Length);
341 |
342 | client.WebSocket.BeginSend (all, 0, all.Length, SocketFlags.None, new AsyncCallback (WebSendCallback), client);
343 | return;
344 | }
345 | }
346 | client.SentHeaders = true;
347 | } else if (client.CurrentPacket != null) {
348 | int length = client.CurrentPacket.Data.Length;
349 |
350 | if (client.CurrentPacket.Data.Length < (client.CurrentPacket.Read + read)) {
351 | //mismatch = true;
352 | Console.WriteLine ("packet length mismatch (should be {0}, but is {1})", client.CurrentPacket.Data.Length, (client.CurrentPacket.Read + read));
353 |
354 | Array.Resize (ref client.CurrentPacket.Data, client.CurrentPacket.Read + read);
355 | Array.Copy (client.WriteBuffer, 0, client.CurrentPacket.Data, client.CurrentPacket.Read, read);
356 |
357 | }
358 | for (int i = client.CurrentPacket.Read; i < client.CurrentPacket.Read + read; i++)
359 | client.CurrentPacket.Data [i] ^= client.CurrentPacket.Mask [i % 4];
360 | client.CurrentPacket.Read += read;
361 |
362 | if (client.CurrentPacket.Read >= client.CurrentPacket.Data.Length) {
363 | OnReceiveFromWebSocket (client, client.CurrentPacket.Data, length);
364 | client.CurrentPacket = null;
365 | }
366 | } else {
367 | byte zero = client.WriteBuffer [0];
368 | byte one = client.WriteBuffer [1];
369 | bool fin = (zero & 0x80) == 0x80;
370 | byte opCode = (byte)((zero & 0x8) | (zero & 0x4) | (zero & 0x2) | (zero & 0x1));
371 |
372 | switch (opCode) {
373 | case 0x08:
374 | {
375 | Console.WriteLine ("Client [{0}]: Closing Connection (browser sent 0x08)", client.WebSocket.RemoteEndPoint);
376 | client.Close ();
377 | return;
378 | }
379 | }
380 |
381 | bool mask = (one & 0x80) == 0x80;
382 | byte payload = (byte)((one & 0x40) | (one & 0x20) | (one & 0x10) | (one & 0x8) | (one & 0x4) | (one & 0x2) | (one & 0x1));
383 | int length = 0;
384 | int s = 0;
385 |
386 | switch (payload) {
387 | case 126:
388 | //16-bit
389 | length = (int)((client.WriteBuffer [2] << 8) | client.WriteBuffer [3]);
390 | s = 2;
391 | break;
392 | case 127:
393 | //32-bit???
394 | UOJS.Log ("Client [{0}]: Got a really big packet (over 16-bits size), so I'll just kill it...", client.WebSocket.RemoteEndPoint);
395 | client.Close ();
396 | return;
397 |
398 | default:
399 | //8-bit
400 | length = payload;
401 | break;
402 | }
403 |
404 | client.CurrentPacket = new WebSocketPacket ();
405 | if (mask) {
406 | // create the bit mask?
407 | // I'm still unsure why the masked is being forced
408 | // in the websocket protocol. oh well.
409 | client.CurrentPacket.Mask = new byte[] {
410 | client.WriteBuffer [s + 2],
411 | client.WriteBuffer [s + 3],
412 | client.WriteBuffer [s + 4],
413 | client.WriteBuffer [s + 5]
414 | };
415 | s += 6;
416 | }
417 |
418 | client.CurrentPacket.Data = new byte[length];
419 | client.CurrentPacket.Read += read - s;
420 |
421 |
422 | Array.Copy (client.WriteBuffer, s, client.CurrentPacket.Data, 0, Math.Min (client.CurrentPacket.Read, client.CurrentPacket.Data.Length));
423 | if (mask)
424 | for (int i = 0; i < client.CurrentPacket.Data.Length; i++)
425 | client.CurrentPacket.Data [i] ^= client.CurrentPacket.Mask [i % 4];
426 | if (client.CurrentPacket.Read == client.CurrentPacket.Data.Length) {
427 | OnReceiveFromWebSocket (client, client.CurrentPacket.Data, client.CurrentPacket.Data.Length);
428 | client.CurrentPacket = null;
429 | }
430 | }
431 | if (webSocket != null && webSocket.Connected)
432 | webSocket.BeginReceive (client.WriteBuffer, 0, WebSocketClient.MaxBufferSize, SocketFlags.None, new AsyncCallback (ReadCallback), client);
433 | } else {
434 | UOJS.Log ("Client [disposed]: No data @ ReadCallback");
435 | }
436 | }
437 |
438 |
439 | public static void OnReceiveFromWebSocket (WebSocketClient client, byte[] data, int length)
440 | {
441 | try {
442 | switch ((char)data [0]) {
443 | // Reconnect
444 | case 'R':
445 | {
446 | if (client.UOSocket != null && client.UOSocket.Connected)
447 | client.UOSocket.Close ();
448 | goto case 'C';
449 | }
450 |
451 | // Connect
452 | case 'C':
453 | {
454 | string[] strData = Encoding.ASCII.GetString (data, 0, data.Length).Split (' ');
455 | for (int i = 0; i < strData.Length; i++)
456 | Console.Write (strData [i] + ",");
457 | client.UOSocket = new Socket (AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
458 | Console.WriteLine (string.Join (",", strData));
459 | client.UOSocket.BeginConnect (strData [1], int.Parse (strData [2]), new AsyncCallback (UOConnectCallback), client);
460 | break;
461 | }
462 |
463 | // Version
464 | case 'V':
465 | {
466 | GameProxy.Send (client, "Version {0}", UOJS.Version);
467 | break;
468 | }
469 |
470 |
471 | default:
472 | {
473 | client.UOSocket.BeginSend (data, 0, data.Length, SocketFlags.None, new AsyncCallback (UOSendCallback), client);
474 | break;
475 | }
476 | }
477 | } catch (Exception e) {
478 | UOJS.Log ("Client [d/c]: Threw {0}... closing!", e.GetType ());
479 | UOJS.Log (e.StackTrace);
480 | client.Close ();
481 | }
482 | }
483 |
484 | public static void UOSendCallback (IAsyncResult ar)
485 | {
486 | WebSocketClient client = (WebSocketClient)ar.AsyncState;
487 |
488 | if (client.UOSocket != null && client.UOSocket.Connected)
489 | client.UOSocket.EndSend (ar);
490 | }
491 | public static void UOReceiveCallback (IAsyncResult ar)
492 | {
493 | WebSocketClient client = (WebSocketClient)ar.AsyncState;
494 | int rec;
495 | try {
496 | rec = (client.UOSocket != null && client.UOSocket.Connected) ? client.UOSocket.EndReceive (ar) : 0;
497 | } catch (Exception e) {
498 | rec = 0;
499 | }
500 | if (rec > 0) {
501 | byte[] buffer = new byte[rec];
502 | Array.Copy (client.UOWriteBuffer, buffer, rec);
503 |
504 | /*if (client.Compressed)
505 | Huffman.Decompress(client, buffer);
506 | else*/
507 |
508 | //byte[] buff = new byte[rec];
509 | //Array.Copy(client.UOWriteBuffer, buff, rec);
510 | Send (client, buffer, RequestType.GameRequest, false);
511 |
512 | //Send(client, Convert.ToBase64String(buff));
513 | if (client.UOSocket != null && client.UOSocket.Connected)
514 | client.UOSocket.BeginReceive (client.UOWriteBuffer, 0, client.UOWriteBuffer.Length, SocketFlags.None, new AsyncCallback (UOReceiveCallback), client);
515 | } else
516 | if (client.UOSocket != null && client.UOSocket.Connected) {
517 | Console.WriteLine ("Client [{0}]: No data", client.WebSocket.RemoteEndPoint);
518 | Send (client, "Discon");
519 | client.Close ();
520 | }
521 | //else close?
522 | }
523 | public static void UOConnectCallback (IAsyncResult ar)
524 | {
525 | WebSocketClient client = (WebSocketClient)ar.AsyncState;
526 | try {
527 | client.UOSocket.EndConnect (ar);
528 | Send (client, "ConSuccess", client.UOSocket.RemoteEndPoint);
529 | client.UOSocket.BeginReceive (client.UOWriteBuffer, 0, client.UOWriteBuffer.Length, SocketFlags.None, new AsyncCallback (UOReceiveCallback), client);
530 | } catch (Exception e) {
531 | Send (client, "ConFail");
532 | }
533 | //Send(client, Encoding.ASCII.GetBytes("L Connected: " + client.UOSocket.RemoteEndPoint
534 | }
535 |
536 | public struct TileInfo
537 | {
538 | public bool IsLand;
539 | public int ID, Z, Hue;
540 |
541 | public TileInfo (bool land, int id, int z, int hue)
542 | {
543 | IsLand = land;
544 | ID = id;
545 | Z = z;
546 | Hue = hue;
547 | }
548 | }
549 |
550 | public static Dictionary m_Widths;
551 |
552 | //[DllImport("./Ultima.dll", EntryPoint="?GetTileDataInfo@UltimaApi@@QAEXH@Z",CallingConvention=CallingConvention.ThisCall)]
553 | //static extern Dictionary GetTileDataInfo (int id);
554 | public static Dictionary ParseVars (string uri)
555 | {
556 | Dictionary vars = new Dictionary ();
557 | MatchCollection col = Regex.Matches (uri, @"([A-Za-z0-9]+)=([A-Za-z0-9]+)");
558 | foreach (Match m in col)
559 | vars.Add (m.Groups [1].Value, m.Groups [2].Value);
560 |
561 | return vars;
562 | }
563 |
564 |
565 | public static byte[] ParseWebRequest (WebSocketClient client, string shortUri, string fullUri)
566 | {
567 | try {
568 | switch (shortUri) {
569 | case "/td":
570 | {
571 | Dictionary query = ParseVars (fullUri);
572 | int id = int.Parse (query ["id"]);
573 | Dictionary dict = new Dictionary ();
574 |
575 | PropertyInfo info = m_Ultima.GetType ("Ultima.TileData").GetProperty ("ItemTable", BindingFlags.Public | BindingFlags.Static | BindingFlags.FlattenHierarchy);
576 | Type itemData = m_Ultima.GetType ("Ultima.ItemData");
577 | object o = ((Array)info.GetValue (null, null)).GetValue (id);
578 | PropertyInfo[] pubInfo = itemData.GetProperties ();
579 | foreach (PropertyInfo p in pubInfo)
580 | dict.Add (p.Name, p.GetValue (o, null).ToString ());
581 |
582 | return m_Encoding.GetBytes (LitJson.JsonMapper.ToJson (dict));
583 | }
584 |
585 | case "/getmapinfo":
586 | {
587 | Dictionary query = ParseVars (fullUri);
588 | int x = int.Parse (query ["x"]), y = int.Parse (query ["y"]), range = int.Parse (query ["r"]);
589 | char facet = query ["m"] [0];
590 | string map;
591 |
592 | switch (facet) {
593 | default:
594 | case 'f':
595 | map = "Felucca";
596 | break;
597 | case 't':
598 | map = "Trammel";
599 | break;
600 | case 'i':
601 | map = "Ilshenar";
602 | break;
603 | case 'm':
604 | map = "Malas";
605 | break;
606 | case 'o':
607 | map = "Tokuno";
608 | break; // whoops
609 | }
610 |
611 | Type Map = m_Ultima.GetType ("Ultima.Map");
612 | Type Tile = m_Ultima.GetType ("Ultima.Tile");
613 | Type HuedTile = m_Ultima.GetType ("Ultima.HuedTile");
614 | Type TileMatrix = m_Ultima.GetType ("Ultima.TileMatrix");
615 | Dictionary>> data
616 | = new Dictionary>> ();
617 | object currentMap = ((FieldInfo)Map.GetMember (map) [0]).GetValue (null);
618 | object tiles = Map.GetProperty ("Tiles").GetValue (currentMap, null);
619 |
620 | for (int i = 0; i < range; i++) {
621 | Dictionary> row;
622 | data.Add ((i + x).ToString (), row = new Dictionary> ());
623 |
624 | for (int j = 0; j < range; j++) {
625 | Dictionary cell = new Dictionary ();
626 | object landTile = TileMatrix.GetMethod ("GetLandTile").Invoke (tiles, new object[]{x + i, y + j});
627 | Array staticTiles = (Array)TileMatrix.GetMethod ("GetStaticTiles").Invoke (tiles, new object[]{x + i, y + j});
628 | int id = (int)Tile.GetProperty ("ID").GetValue (landTile, null);
629 | int z = (int)Tile.GetProperty ("Z").GetValue (landTile, null);
630 |
631 | cell.Add ("id", id);
632 | cell.Add ("z", z);
633 | cell.Add ("length", staticTiles.Length);
634 | TileInfo[] stiles = new TileInfo[staticTiles.Length];
635 | for (int k = 0; k < stiles.Length; k++) {
636 | stiles [k].ID = (int)(HuedTile.GetProperty ("ID").GetValue (staticTiles.GetValue (k), null)) % 0x4000;
637 |
638 | stiles [k].Hue = (int)HuedTile.GetProperty ("Hue").GetValue (staticTiles.GetValue (k), null);
639 | stiles [k].Z = (int)HuedTile.GetProperty ("Z").GetValue (staticTiles.GetValue (k), null);
640 | }
641 | cell.Add ("o", stiles);
642 | row.Add ((j + y).ToString (), cell);
643 | }
644 | }
645 |
646 | return m_Encoding.GetBytes (LitJson.JsonMapper.ToJson (data));
647 | }
648 |
649 |
650 | case "/getgump":
651 | {
652 | Dictionary query = ParseVars (fullUri);
653 | foreach (KeyValuePair kvp in query)
654 | Console.WriteLine (kvp);
655 | int id = int.Parse (query ["id"]);
656 | Type Gumps = m_Ultima.GetType ("Ultima.Gumps");
657 |
658 | //int hueIdx = int.Parse (query ["h"]);
659 |
660 | //Hue hue = hueIdx == 0 ? null : Hues.List [(hueIdx & 0x3FFF) - 1];
661 |
662 | //Bitmap b = (Bitmap)(Gumps.GetGump (id).Clone ());
663 |
664 | Bitmap b = (Bitmap)Gumps.GetMethod ("GetGump", new Type[]{typeof(Int32)}).Invoke (null, new object[]{id});
665 | //if (hue != null)
666 | // hue.ApplyTo (b, true);
667 |
668 | MemoryStream ms = new MemoryStream ();
669 | b.Save (ms, System.Drawing.Imaging.ImageFormat.Png);
670 |
671 | return ms.GetBuffer ();
672 | }
673 |
674 | case "/getobj":
675 | {
676 | Dictionary query = ParseVars (fullUri);
677 | char type = query ["t"] [0];
678 | int id = int.Parse (query ["i"]);
679 | int hueIdx = int.Parse (query ["h"]);
680 |
681 | string crop = query.ContainsKey ("c") ? query ["c"] : "";
682 | Type Art = m_Ultima.GetType ("Ultima.Art");
683 | Bitmap b = (Bitmap)(Art.GetMethod (type == 'l' ? "GetLand" : "GetStatic", new Type[]{typeof(Int32)}).Invoke (null, new object[]{id}));
684 | //Bitmap b = (Bitmap)(type == 'l' ? Art.GetLand (id) : Art.GetStatic (id)); //don't hue the cached, clone it
685 | //if (b == null)
686 | // b = Art.GetLand (0);
687 | b = (Bitmap)b.Clone ();
688 |
689 | //TODO: clone before hue (prevent modifying cache object)
690 | //Hue hue = hueIdx == 0 ? null : Hues.List [(hueIdx & 0x3FFF) - 1];
691 | //if (hue != null)
692 | // hue.ApplyTo (b, type == 'l');
693 |
694 | switch (crop) {
695 | // why can't this be done on the client side by only drawing half after
696 | // the transformation? set the sX to the half or set the sW to the half
697 | // depending on the side??
698 | case "right":
699 | {
700 | for (int x = 0; x < b.Width/2; x++) {
701 | for (int y = 0; y < b.Height; y++) {
702 | b.SetPixel (x, y, Color.Transparent);
703 | }
704 | }
705 | break;
706 | }
707 | case "left":
708 | {
709 | for (int x = b.Width/2; x < b.Width; x++) {
710 | for (int y = 0; y < b.Height; y++) {
711 | b.SetPixel (x, y, Color.Transparent);
712 | }
713 | }
714 | break;
715 | }
716 | }
717 | MemoryStream ms = new MemoryStream ();
718 | b.Save (ms, System.Drawing.Imaging.ImageFormat.Png);
719 | return ms.GetBuffer ();
720 | }
721 |
722 | case "/getcliloc":
723 | {
724 | Dictionary query = ParseVars (fullUri);
725 | int message = int.Parse (query ["i"]), i = 0;
726 | Type StringList = m_Ultima.GetType ("Ultima.StringList");
727 | System.Collections.Hashtable table = (System.Collections.Hashtable)StringList.GetProperty ("Table").GetValue (StringList.GetProperty ("EnglishStringList", BindingFlags.Public | BindingFlags.Static | BindingFlags.FlattenHierarchy).GetValue (null, null), null);
728 | if (!table.ContainsKey (message))
729 | return m_Encoding.GetBytes ("{\"text\": null}");
730 |
731 | string entry = (string)table [message];
732 |
733 | return UTF8Encoding.UTF8.GetBytes (entry);
734 | //string replace = Regex.Replace (entry, @"~[A-Za-z0-9_]+~", match => (query.ContainsKey ("" + (++i)) ? query ["" + (i)] : ""));
735 |
736 | //return UTF8Encoding.UTF8.GetBytes ("{\"text\":\"" + replace.Replace ("\"", "\\\"") + "\"}");
737 | }
738 |
739 | case "/getaniminfo":
740 | {
741 | Dictionary query = ParseVars (fullUri);
742 | int bodyId = int.Parse (query ["i"]);
743 | int action = int.Parse (query ["a"]);
744 | int dir = int.Parse (query ["d"]);
745 | int hash = (bodyId << 16) | (action << 8) | (dir);
746 | byte[] widths = null;
747 |
748 | if (m_Widths.ContainsKey (hash))
749 | widths = m_Widths [hash];
750 | else {
751 | Type Animations = m_Ultima.GetType ("Ultima.Animations");
752 | Type Frame = m_Ultima.GetType ("Ultima.Frame");
753 | Array frames = (Array)Animations.GetMethod ("GetAnimation").Invoke (null, new object[] {
754 | bodyId,
755 | action,
756 | dir,
757 | 0,
758 | true
759 | });
760 | //Frame[] frames = Animations.GetAnimation (bodyId, action, dir, 0, true);
761 |
762 | if (frames == null)
763 | widths = new byte[0];
764 | else {
765 | widths = new byte[frames.Length];
766 | for (int i = 0; i < frames.Length; i++) {
767 | System.Drawing.Bitmap b = (System.Drawing.Bitmap)Frame.GetProperty ("Bitmap").GetValue (frames.GetValue (i), null);
768 | widths [i] = (byte)b.Width;
769 | }
770 | }
771 | }
772 | List tmp = new List ();
773 | foreach (byte b in widths)
774 | tmp.Add (b.ToString ());
775 |
776 | return ASCIIEncoding.ASCII.GetBytes ("{\"widths\": [" + string.Join (",", tmp.ToArray ()) + "]}");
777 | }
778 |
779 | case "/getanim":
780 | {
781 | //todo: check if wearable and adjust bitmap accordingly if human
782 | Dictionary query = ParseVars (fullUri);
783 | int bodyId = int.Parse (query ["i"]);
784 | int action = int.Parse (query ["a"]);
785 | int dir = int.Parse (query ["d"]);
786 | int hueIdx = int.Parse (query ["h"]);
787 | Type Animations = m_Ultima.GetType ("Ultima.Animations");
788 | Type Frame = m_Ultima.GetType ("Ultima.Frame");
789 | Array frames = (Array)Animations.GetMethod ("GetAnimation").Invoke (null, new object[] {
790 | bodyId,
791 | action,
792 | dir,
793 | 0,
794 | true
795 | });
796 | //Frame[] frames = Animations.GetAnimation (bodyId, action, dir, 0, true);
797 | //Hue hue = hueIdx == 0 ? null : Hues.List [(hueIdx & 0x3FFF) - 1];
798 | int hash = (bodyId << 16) | (action << 8) | (dir);
799 | if (frames == null)
800 | return new byte[] { };
801 |
802 | int maxWidth = 0, maxHeight = 0;
803 | for (int i = 0; i < frames.Length; i++) {
804 | System.Drawing.Bitmap b = (System.Drawing.Bitmap)Frame.GetProperty ("Bitmap").GetValue (frames.GetValue (i), null);
805 | if (b.Width > maxWidth)
806 | maxWidth = b.Width; // +Math.Abs(frame.Center.X);
807 | if (b.Height > maxHeight)
808 | maxHeight = b.Height; // +Math.Abs(frame.Center.Y);
809 | }
810 | // should we cache full animation bitmaps?
811 | Bitmap bitmap = new Bitmap (maxWidth * frames.Length, maxHeight);
812 | Graphics g = Graphics.FromImage (bitmap);
813 |
814 | byte[] widths = new byte[frames.Length];
815 | for (int i = 0; i < frames.Length; i++) {
816 | object frame = frames.GetValue (i);
817 | System.Drawing.Bitmap single = (System.Drawing.Bitmap)Frame.GetProperty ("Bitmap").GetValue (frames.GetValue (i), null);
818 |
819 | widths [i] = (byte)single.Width;
820 | g.DrawImageUnscaled (single, i * maxWidth, 0);
821 | }
822 | if (!m_Widths.ContainsKey (hash))
823 | m_Widths.Add (hash, widths);
824 | //if (hueIdx != 0)
825 | // hue.ApplyTo (bitmap, TileData.AnimationData.ContainsKey (bodyId) && (TileData.AnimationData [bodyId].Flags & TileFlag.PartialHue) != 0);
826 | bitmap.SetPixel (0, 0, Color.FromArgb (0, 0, 0, frames.Length));
827 | MemoryStream ms = new MemoryStream ();
828 | bitmap.Save (ms, System.Drawing.Imaging.ImageFormat.Png);
829 | return ms.GetBuffer ();
830 | }
831 | }
832 | } catch (Exception e) {
833 | UOJS.Log ("Error {0}\r\n{1}", e.Message, e.StackTrace);
834 | return ASCIIEncoding.ASCII.GetBytes (string.Format ("An error has occurred: {0}\r\n{1}", e.Message, e.StackTrace));
835 |
836 | }
837 | return new byte[] { };
838 | }
839 |
840 | #region Sending
841 | public static void Send (WebSocketClient client, string format, params object[] o)
842 | {
843 | GameProxy.Send (client, m_Encoding.GetBytes (string.Format (format, o)), RequestType.WebRequest, false);
844 | }
845 |
846 | public static void Send (WebSocketClient client, byte[] data, RequestType type, bool mask)
847 | {
848 | // masking isn't needed?
849 | int headerLength = 2;
850 | byte payload = 0;
851 | byte[] maskKeys = null;
852 | byte[] tmp = new byte[data.Length + 1];
853 | tmp [0] = (byte)type;
854 | Array.Copy (data, 0, tmp, 1, data.Length);
855 | data = tmp;
856 |
857 | //data = Encoding.UTF8.GetBytes(((char)type) + Convert.ToBase64String(data));
858 |
859 | //data = Encoding.UTF8.GetBytes(Encoding.ASCII.GetString(data));
860 | //Console.WriteLine("Raw length={0}", data.Length);
861 | if (data.Length > short.MaxValue)
862 | UOJS.Log ("Client [{0}]: Sending Really Large Packet (not implemented)", client.WebSocket.RemoteEndPoint);
863 | if (data.Length >= 126) {
864 | headerLength += 2;
865 | payload = 126;
866 | } else
867 | payload = (byte)data.Length;
868 | if (mask) {
869 | headerLength += 4;
870 | Random r = new Random ();
871 | maskKeys = new byte[] { 1, 2, 3, 4 };
872 | r.NextBytes (maskKeys);
873 | }
874 |
875 | byte[] allData = new byte[headerLength + data.Length];
876 | allData [0] = 0x80 | 0x02;
877 | allData [1] = (byte)((mask ? 0x80 : 0) | payload & 0x40 | payload & 0x20 | payload & 0x10 | payload & 0x8 | payload & 0x4 | payload & 0x2 | payload & 0x1);
878 |
879 | if (payload == 126) {
880 | byte[] lengthBytes = BitConverter.GetBytes ((ushort)data.Length);
881 | allData [2] = lengthBytes [1]; // (byte)((data.Length >> 8) & 0xFF);
882 | allData [3] = lengthBytes [0]; // (byte)(data.Length & 0xFF);
883 | }
884 |
885 | Array.Copy (data, 0, allData, headerLength, data.Length);
886 | if (mask) {
887 | Array.Copy (maskKeys, 0, allData, 2, 4);
888 | for (int i = 0; i < data.Length; i++)
889 | allData [i + headerLength] ^= maskKeys [i % 4];
890 | }
891 |
892 |
893 | if (client.WebSocket != null && client.WebSocket.Connected) {
894 | client.WebSocket.BeginSend (allData, 0, allData.Length, SocketFlags.None, new AsyncCallback (SendCallback), client);
895 | }
896 | }
897 | public static void WebSendCallback (IAsyncResult ar)
898 | {
899 | WebSocketClient client = (WebSocketClient)ar.AsyncState;
900 | if (client.WebSocket != null && client.WebSocket.Connected) {
901 | //UOJS.Log ("Client [{0}]: Sent {1} bytes", client.WebSocket.RemoteEndPoint, client.WebSocket != null && client.WebSocket.Connected ? client.WebSocket.EndSend (ar) : 0);
902 | client.Close ();
903 | }
904 | }
905 | public static void SendCallback (IAsyncResult ar)
906 | {
907 | WebSocketClient client = (WebSocketClient)ar.AsyncState;
908 | if (client.WebSocket != null && client.WebSocket.Connected) {
909 | try {
910 | //UOJS.Log ("Client [{0}]: Sent {1} bytes", client.WebSocket.RemoteEndPoint, client.WebSocket != null && client.WebSocket.Connected ? client.WebSocket.EndSend (ar) : 0);
911 | } catch {
912 |
913 | }
914 | }
915 | }
916 | #endregion
917 |
918 | }
919 | }
920 |
921 |
--------------------------------------------------------------------------------
/Scripts/UOJS/UOJS/LitJson/IJsonWrapper.cs:
--------------------------------------------------------------------------------
1 | #region Header
2 | /**
3 | * IJsonWrapper.cs
4 | * Interface that represents a type capable of handling all kinds of JSON
5 | * data. This is mainly used when mapping objects through JsonMapper, and
6 | * it's implemented by JsonData.
7 | *
8 | * The authors disclaim copyright to this source code. For more details, see
9 | * the COPYING file included with this distribution.
10 | **/
11 | #endregion
12 |
13 |
14 | using System.Collections;
15 | using System.Collections.Specialized;
16 |
17 |
18 | namespace LitJson
19 | {
20 | public enum JsonType
21 | {
22 | None,
23 |
24 | Object,
25 | Array,
26 | String,
27 | Int,
28 | Long,
29 | Double,
30 | Boolean
31 | }
32 |
33 | public interface IJsonWrapper : IList, IOrderedDictionary
34 | {
35 | bool IsArray { get; }
36 | bool IsBoolean { get; }
37 | bool IsDouble { get; }
38 | bool IsInt { get; }
39 | bool IsLong { get; }
40 | bool IsObject { get; }
41 | bool IsString { get; }
42 |
43 | bool GetBoolean ();
44 | double GetDouble ();
45 | int GetInt ();
46 | JsonType GetJsonType ();
47 | long GetLong ();
48 | string GetString ();
49 |
50 | void SetBoolean (bool val);
51 | void SetDouble (double val);
52 | void SetInt (int val);
53 | void SetJsonType (JsonType type);
54 | void SetLong (long val);
55 | void SetString (string val);
56 |
57 | string ToJson ();
58 | void ToJson (JsonWriter writer);
59 | }
60 | }
61 |
--------------------------------------------------------------------------------
/Scripts/UOJS/UOJS/LitJson/JsonData.cs:
--------------------------------------------------------------------------------
1 | #region Header
2 | /**
3 | * JsonData.cs
4 | * Generic type to hold JSON data (objects, arrays, and so on). This is
5 | * the default type returned by JsonMapper.ToObject().
6 | *
7 | * The authors disclaim copyright to this source code. For more details, see
8 | * the COPYING file included with this distribution.
9 | **/
10 | #endregion
11 |
12 |
13 | using System;
14 | using System.Collections;
15 | using System.Collections.Generic;
16 | using System.Collections.Specialized;
17 | using System.IO;
18 |
19 |
20 | namespace LitJson
21 | {
22 | public class JsonData : IJsonWrapper, IEquatable
23 | {
24 | #region Fields
25 | private IList inst_array;
26 | private bool inst_boolean;
27 | private double inst_double;
28 | private int inst_int;
29 | private long inst_long;
30 | private IDictionary inst_object;
31 | private string inst_string;
32 | private string json;
33 | private JsonType type;
34 |
35 | // Used to implement the IOrderedDictionary interface
36 | private IList> object_list;
37 | #endregion
38 |
39 |
40 | #region Properties
41 | public int Count {
42 | get { return EnsureCollection ().Count; }
43 | }
44 |
45 | public bool IsArray {
46 | get { return type == JsonType.Array; }
47 | }
48 |
49 | public bool IsBoolean {
50 | get { return type == JsonType.Boolean; }
51 | }
52 |
53 | public bool IsDouble {
54 | get { return type == JsonType.Double; }
55 | }
56 |
57 | public bool IsInt {
58 | get { return type == JsonType.Int; }
59 | }
60 |
61 | public bool IsLong {
62 | get { return type == JsonType.Long; }
63 | }
64 |
65 | public bool IsObject {
66 | get { return type == JsonType.Object; }
67 | }
68 |
69 | public bool IsString {
70 | get { return type == JsonType.String; }
71 | }
72 | #endregion
73 |
74 |
75 | #region ICollection Properties
76 | int ICollection.Count {
77 | get {
78 | return Count;
79 | }
80 | }
81 |
82 | bool ICollection.IsSynchronized {
83 | get {
84 | return EnsureCollection ().IsSynchronized;
85 | }
86 | }
87 |
88 | object ICollection.SyncRoot {
89 | get {
90 | return EnsureCollection ().SyncRoot;
91 | }
92 | }
93 | #endregion
94 |
95 |
96 | #region IDictionary Properties
97 | bool IDictionary.IsFixedSize {
98 | get {
99 | return EnsureDictionary ().IsFixedSize;
100 | }
101 | }
102 |
103 | bool IDictionary.IsReadOnly {
104 | get {
105 | return EnsureDictionary ().IsReadOnly;
106 | }
107 | }
108 |
109 | ICollection IDictionary.Keys {
110 | get {
111 | EnsureDictionary ();
112 | IList keys = new List ();
113 |
114 | foreach (KeyValuePair entry in
115 | object_list) {
116 | keys.Add (entry.Key);
117 | }
118 |
119 | return (ICollection) keys;
120 | }
121 | }
122 |
123 | ICollection IDictionary.Values {
124 | get {
125 | EnsureDictionary ();
126 | IList values = new List ();
127 |
128 | foreach (KeyValuePair entry in
129 | object_list) {
130 | values.Add (entry.Value);
131 | }
132 |
133 | return (ICollection) values;
134 | }
135 | }
136 | #endregion
137 |
138 |
139 |
140 | #region IJsonWrapper Properties
141 | bool IJsonWrapper.IsArray {
142 | get { return IsArray; }
143 | }
144 |
145 | bool IJsonWrapper.IsBoolean {
146 | get { return IsBoolean; }
147 | }
148 |
149 | bool IJsonWrapper.IsDouble {
150 | get { return IsDouble; }
151 | }
152 |
153 | bool IJsonWrapper.IsInt {
154 | get { return IsInt; }
155 | }
156 |
157 | bool IJsonWrapper.IsLong {
158 | get { return IsLong; }
159 | }
160 |
161 | bool IJsonWrapper.IsObject {
162 | get { return IsObject; }
163 | }
164 |
165 | bool IJsonWrapper.IsString {
166 | get { return IsString; }
167 | }
168 | #endregion
169 |
170 |
171 | #region IList Properties
172 | bool IList.IsFixedSize {
173 | get {
174 | return EnsureList ().IsFixedSize;
175 | }
176 | }
177 |
178 | bool IList.IsReadOnly {
179 | get {
180 | return EnsureList ().IsReadOnly;
181 | }
182 | }
183 | #endregion
184 |
185 |
186 | #region IDictionary Indexer
187 | object IDictionary.this[object key] {
188 | get {
189 | return EnsureDictionary ()[key];
190 | }
191 |
192 | set {
193 | if (! (key is String))
194 | throw new ArgumentException (
195 | "The key has to be a string");
196 |
197 | JsonData data = ToJsonData (value);
198 |
199 | this[(string) key] = data;
200 | }
201 | }
202 | #endregion
203 |
204 |
205 | #region IOrderedDictionary Indexer
206 | object IOrderedDictionary.this[int idx] {
207 | get {
208 | EnsureDictionary ();
209 | return object_list[idx].Value;
210 | }
211 |
212 | set {
213 | EnsureDictionary ();
214 | JsonData data = ToJsonData (value);
215 |
216 | KeyValuePair old_entry = object_list[idx];
217 |
218 | inst_object[old_entry.Key] = data;
219 |
220 | KeyValuePair entry =
221 | new KeyValuePair (old_entry.Key, data);
222 |
223 | object_list[idx] = entry;
224 | }
225 | }
226 | #endregion
227 |
228 |
229 | #region IList Indexer
230 | object IList.this[int index] {
231 | get {
232 | return EnsureList ()[index];
233 | }
234 |
235 | set {
236 | EnsureList ();
237 | JsonData data = ToJsonData (value);
238 |
239 | this[index] = data;
240 | }
241 | }
242 | #endregion
243 |
244 |
245 | #region Public Indexers
246 | public JsonData this[string prop_name] {
247 | get {
248 | EnsureDictionary ();
249 | return inst_object[prop_name];
250 | }
251 |
252 | set {
253 | EnsureDictionary ();
254 |
255 | KeyValuePair entry =
256 | new KeyValuePair (prop_name, value);
257 |
258 | if (inst_object.ContainsKey (prop_name)) {
259 | for (int i = 0; i < object_list.Count; i++) {
260 | if (object_list[i].Key == prop_name) {
261 | object_list[i] = entry;
262 | break;
263 | }
264 | }
265 | } else
266 | object_list.Add (entry);
267 |
268 | inst_object[prop_name] = value;
269 |
270 | json = null;
271 | }
272 | }
273 |
274 | public JsonData this[int index] {
275 | get {
276 | EnsureCollection ();
277 |
278 | if (type == JsonType.Array)
279 | return inst_array[index];
280 |
281 | return object_list[index].Value;
282 | }
283 |
284 | set {
285 | EnsureCollection ();
286 |
287 | if (type == JsonType.Array)
288 | inst_array[index] = value;
289 | else {
290 | KeyValuePair entry = object_list[index];
291 | KeyValuePair new_entry =
292 | new KeyValuePair (entry.Key, value);
293 |
294 | object_list[index] = new_entry;
295 | inst_object[entry.Key] = value;
296 | }
297 |
298 | json = null;
299 | }
300 | }
301 | #endregion
302 |
303 |
304 | #region Constructors
305 | public JsonData ()
306 | {
307 | }
308 |
309 | public JsonData (bool boolean)
310 | {
311 | type = JsonType.Boolean;
312 | inst_boolean = boolean;
313 | }
314 |
315 | public JsonData (double number)
316 | {
317 | type = JsonType.Double;
318 | inst_double = number;
319 | }
320 |
321 | public JsonData (int number)
322 | {
323 | type = JsonType.Int;
324 | inst_int = number;
325 | }
326 |
327 | public JsonData (long number)
328 | {
329 | type = JsonType.Long;
330 | inst_long = number;
331 | }
332 |
333 | public JsonData (object obj)
334 | {
335 | if (obj is Boolean) {
336 | type = JsonType.Boolean;
337 | inst_boolean = (bool) obj;
338 | return;
339 | }
340 |
341 | if (obj is Double) {
342 | type = JsonType.Double;
343 | inst_double = (double) obj;
344 | return;
345 | }
346 |
347 | if (obj is Int32) {
348 | type = JsonType.Int;
349 | inst_int = (int) obj;
350 | return;
351 | }
352 |
353 | if (obj is Int64) {
354 | type = JsonType.Long;
355 | inst_long = (long) obj;
356 | return;
357 | }
358 |
359 | if (obj is String) {
360 | type = JsonType.String;
361 | inst_string = (string) obj;
362 | return;
363 | }
364 |
365 | throw new ArgumentException (
366 | "Unable to wrap the given object with JsonData");
367 | }
368 |
369 | public JsonData (string str)
370 | {
371 | type = JsonType.String;
372 | inst_string = str;
373 | }
374 | #endregion
375 |
376 |
377 | #region Implicit Conversions
378 | public static implicit operator JsonData (Boolean data)
379 | {
380 | return new JsonData (data);
381 | }
382 |
383 | public static implicit operator JsonData (Double data)
384 | {
385 | return new JsonData (data);
386 | }
387 |
388 | public static implicit operator JsonData (Int32 data)
389 | {
390 | return new JsonData (data);
391 | }
392 |
393 | public static implicit operator JsonData (Int64 data)
394 | {
395 | return new JsonData (data);
396 | }
397 |
398 | public static implicit operator JsonData (String data)
399 | {
400 | return new JsonData (data);
401 | }
402 | #endregion
403 |
404 |
405 | #region Explicit Conversions
406 | public static explicit operator Boolean (JsonData data)
407 | {
408 | if (data.type != JsonType.Boolean)
409 | throw new InvalidCastException (
410 | "Instance of JsonData doesn't hold a double");
411 |
412 | return data.inst_boolean;
413 | }
414 |
415 | public static explicit operator Double (JsonData data)
416 | {
417 | if (data.type != JsonType.Double)
418 | throw new InvalidCastException (
419 | "Instance of JsonData doesn't hold a double");
420 |
421 | return data.inst_double;
422 | }
423 |
424 | public static explicit operator Int32 (JsonData data)
425 | {
426 | if (data.type != JsonType.Int)
427 | throw new InvalidCastException (
428 | "Instance of JsonData doesn't hold an int");
429 |
430 | return data.inst_int;
431 | }
432 |
433 | public static explicit operator Int64 (JsonData data)
434 | {
435 | if (data.type != JsonType.Long)
436 | throw new InvalidCastException (
437 | "Instance of JsonData doesn't hold an int");
438 |
439 | return data.inst_long;
440 | }
441 |
442 | public static explicit operator String (JsonData data)
443 | {
444 | if (data.type != JsonType.String)
445 | throw new InvalidCastException (
446 | "Instance of JsonData doesn't hold a string");
447 |
448 | return data.inst_string;
449 | }
450 | #endregion
451 |
452 |
453 | #region ICollection Methods
454 | void ICollection.CopyTo (Array array, int index)
455 | {
456 | EnsureCollection ().CopyTo (array, index);
457 | }
458 | #endregion
459 |
460 |
461 | #region IDictionary Methods
462 | void IDictionary.Add (object key, object value)
463 | {
464 | JsonData data = ToJsonData (value);
465 |
466 | EnsureDictionary ().Add (key, data);
467 |
468 | KeyValuePair entry =
469 | new KeyValuePair ((string) key, data);
470 | object_list.Add (entry);
471 |
472 | json = null;
473 | }
474 |
475 | void IDictionary.Clear ()
476 | {
477 | EnsureDictionary ().Clear ();
478 | object_list.Clear ();
479 | json = null;
480 | }
481 |
482 | bool IDictionary.Contains (object key)
483 | {
484 | return EnsureDictionary ().Contains (key);
485 | }
486 |
487 | IDictionaryEnumerator IDictionary.GetEnumerator ()
488 | {
489 | return ((IOrderedDictionary) this).GetEnumerator ();
490 | }
491 |
492 | void IDictionary.Remove (object key)
493 | {
494 | EnsureDictionary ().Remove (key);
495 |
496 | for (int i = 0; i < object_list.Count; i++) {
497 | if (object_list[i].Key == (string) key) {
498 | object_list.RemoveAt (i);
499 | break;
500 | }
501 | }
502 |
503 | json = null;
504 | }
505 | #endregion
506 |
507 |
508 | #region IEnumerable Methods
509 | IEnumerator IEnumerable.GetEnumerator ()
510 | {
511 | return EnsureCollection ().GetEnumerator ();
512 | }
513 | #endregion
514 |
515 |
516 | #region IJsonWrapper Methods
517 | bool IJsonWrapper.GetBoolean ()
518 | {
519 | if (type != JsonType.Boolean)
520 | throw new InvalidOperationException (
521 | "JsonData instance doesn't hold a boolean");
522 |
523 | return inst_boolean;
524 | }
525 |
526 | double IJsonWrapper.GetDouble ()
527 | {
528 | if (type != JsonType.Double)
529 | throw new InvalidOperationException (
530 | "JsonData instance doesn't hold a double");
531 |
532 | return inst_double;
533 | }
534 |
535 | int IJsonWrapper.GetInt ()
536 | {
537 | if (type != JsonType.Int)
538 | throw new InvalidOperationException (
539 | "JsonData instance doesn't hold an int");
540 |
541 | return inst_int;
542 | }
543 |
544 | long IJsonWrapper.GetLong ()
545 | {
546 | if (type != JsonType.Long)
547 | throw new InvalidOperationException (
548 | "JsonData instance doesn't hold a long");
549 |
550 | return inst_long;
551 | }
552 |
553 | string IJsonWrapper.GetString ()
554 | {
555 | if (type != JsonType.String)
556 | throw new InvalidOperationException (
557 | "JsonData instance doesn't hold a string");
558 |
559 | return inst_string;
560 | }
561 |
562 | void IJsonWrapper.SetBoolean (bool val)
563 | {
564 | type = JsonType.Boolean;
565 | inst_boolean = val;
566 | json = null;
567 | }
568 |
569 | void IJsonWrapper.SetDouble (double val)
570 | {
571 | type = JsonType.Double;
572 | inst_double = val;
573 | json = null;
574 | }
575 |
576 | void IJsonWrapper.SetInt (int val)
577 | {
578 | type = JsonType.Int;
579 | inst_int = val;
580 | json = null;
581 | }
582 |
583 | void IJsonWrapper.SetLong (long val)
584 | {
585 | type = JsonType.Long;
586 | inst_long = val;
587 | json = null;
588 | }
589 |
590 | void IJsonWrapper.SetString (string val)
591 | {
592 | type = JsonType.String;
593 | inst_string = val;
594 | json = null;
595 | }
596 |
597 | string IJsonWrapper.ToJson ()
598 | {
599 | return ToJson ();
600 | }
601 |
602 | void IJsonWrapper.ToJson (JsonWriter writer)
603 | {
604 | ToJson (writer);
605 | }
606 | #endregion
607 |
608 |
609 | #region IList Methods
610 | int IList.Add (object value)
611 | {
612 | return Add (value);
613 | }
614 |
615 | void IList.Clear ()
616 | {
617 | EnsureList ().Clear ();
618 | json = null;
619 | }
620 |
621 | bool IList.Contains (object value)
622 | {
623 | return EnsureList ().Contains (value);
624 | }
625 |
626 | int IList.IndexOf (object value)
627 | {
628 | return EnsureList ().IndexOf (value);
629 | }
630 |
631 | void IList.Insert (int index, object value)
632 | {
633 | EnsureList ().Insert (index, value);
634 | json = null;
635 | }
636 |
637 | void IList.Remove (object value)
638 | {
639 | EnsureList ().Remove (value);
640 | json = null;
641 | }
642 |
643 | void IList.RemoveAt (int index)
644 | {
645 | EnsureList ().RemoveAt (index);
646 | json = null;
647 | }
648 | #endregion
649 |
650 |
651 | #region IOrderedDictionary Methods
652 | IDictionaryEnumerator IOrderedDictionary.GetEnumerator ()
653 | {
654 | EnsureDictionary ();
655 |
656 | return new OrderedDictionaryEnumerator (
657 | object_list.GetEnumerator ());
658 | }
659 |
660 | void IOrderedDictionary.Insert (int idx, object key, object value)
661 | {
662 | string property = (string) key;
663 | JsonData data = ToJsonData (value);
664 |
665 | this[property] = data;
666 |
667 | KeyValuePair entry =
668 | new KeyValuePair (property, data);
669 |
670 | object_list.Insert (idx, entry);
671 | }
672 |
673 | void IOrderedDictionary.RemoveAt (int idx)
674 | {
675 | EnsureDictionary ();
676 |
677 | inst_object.Remove (object_list[idx].Key);
678 | object_list.RemoveAt (idx);
679 | }
680 | #endregion
681 |
682 |
683 | #region Private Methods
684 | private ICollection EnsureCollection ()
685 | {
686 | if (type == JsonType.Array)
687 | return (ICollection) inst_array;
688 |
689 | if (type == JsonType.Object)
690 | return (ICollection) inst_object;
691 |
692 | throw new InvalidOperationException (
693 | "The JsonData instance has to be initialized first");
694 | }
695 |
696 | private IDictionary EnsureDictionary ()
697 | {
698 | if (type == JsonType.Object)
699 | return (IDictionary) inst_object;
700 |
701 | if (type != JsonType.None)
702 | throw new InvalidOperationException (
703 | "Instance of JsonData is not a dictionary");
704 |
705 | type = JsonType.Object;
706 | inst_object = new Dictionary ();
707 | object_list = new List> ();
708 |
709 | return (IDictionary) inst_object;
710 | }
711 |
712 | private IList EnsureList ()
713 | {
714 | if (type == JsonType.Array)
715 | return (IList) inst_array;
716 |
717 | if (type != JsonType.None)
718 | throw new InvalidOperationException (
719 | "Instance of JsonData is not a list");
720 |
721 | type = JsonType.Array;
722 | inst_array = new List ();
723 |
724 | return (IList) inst_array;
725 | }
726 |
727 | private JsonData ToJsonData (object obj)
728 | {
729 | if (obj == null)
730 | return null;
731 |
732 | if (obj is JsonData)
733 | return (JsonData) obj;
734 |
735 | return new JsonData (obj);
736 | }
737 |
738 | private static void WriteJson (IJsonWrapper obj, JsonWriter writer)
739 | {
740 | if (obj == null) {
741 | writer.Write (null);
742 | return;
743 | }
744 |
745 | if (obj.IsString) {
746 | writer.Write (obj.GetString ());
747 | return;
748 | }
749 |
750 | if (obj.IsBoolean) {
751 | writer.Write (obj.GetBoolean ());
752 | return;
753 | }
754 |
755 | if (obj.IsDouble) {
756 | writer.Write (obj.GetDouble ());
757 | return;
758 | }
759 |
760 | if (obj.IsInt) {
761 | writer.Write (obj.GetInt ());
762 | return;
763 | }
764 |
765 | if (obj.IsLong) {
766 | writer.Write (obj.GetLong ());
767 | return;
768 | }
769 |
770 | if (obj.IsArray) {
771 | writer.WriteArrayStart ();
772 | foreach (object elem in (IList) obj)
773 | WriteJson ((JsonData) elem, writer);
774 | writer.WriteArrayEnd ();
775 |
776 | return;
777 | }
778 |
779 | if (obj.IsObject) {
780 | writer.WriteObjectStart ();
781 |
782 | foreach (DictionaryEntry entry in ((IDictionary) obj)) {
783 | writer.WritePropertyName ((string) entry.Key);
784 | WriteJson ((JsonData) entry.Value, writer);
785 | }
786 | writer.WriteObjectEnd ();
787 |
788 | return;
789 | }
790 | }
791 | #endregion
792 |
793 |
794 | public int Add (object value)
795 | {
796 | JsonData data = ToJsonData (value);
797 |
798 | json = null;
799 |
800 | return EnsureList ().Add (data);
801 | }
802 |
803 | public void Clear ()
804 | {
805 | if (IsObject) {
806 | ((IDictionary) this).Clear ();
807 | return;
808 | }
809 |
810 | if (IsArray) {
811 | ((IList) this).Clear ();
812 | return;
813 | }
814 | }
815 |
816 | public bool Equals (JsonData x)
817 | {
818 | if (x == null)
819 | return false;
820 |
821 | if (x.type != this.type)
822 | return false;
823 |
824 | switch (this.type) {
825 | case JsonType.None:
826 | return true;
827 |
828 | case JsonType.Object:
829 | return this.inst_object.Equals (x.inst_object);
830 |
831 | case JsonType.Array:
832 | return this.inst_array.Equals (x.inst_array);
833 |
834 | case JsonType.String:
835 | return this.inst_string.Equals (x.inst_string);
836 |
837 | case JsonType.Int:
838 | return this.inst_int.Equals (x.inst_int);
839 |
840 | case JsonType.Long:
841 | return this.inst_long.Equals (x.inst_long);
842 |
843 | case JsonType.Double:
844 | return this.inst_double.Equals (x.inst_double);
845 |
846 | case JsonType.Boolean:
847 | return this.inst_boolean.Equals (x.inst_boolean);
848 | }
849 |
850 | return false;
851 | }
852 |
853 | public JsonType GetJsonType ()
854 | {
855 | return type;
856 | }
857 |
858 | public void SetJsonType (JsonType type)
859 | {
860 | if (this.type == type)
861 | return;
862 |
863 | switch (type) {
864 | case JsonType.None:
865 | break;
866 |
867 | case JsonType.Object:
868 | inst_object = new Dictionary ();
869 | object_list = new List> ();
870 | break;
871 |
872 | case JsonType.Array:
873 | inst_array = new List ();
874 | break;
875 |
876 | case JsonType.String:
877 | inst_string = default (String);
878 | break;
879 |
880 | case JsonType.Int:
881 | inst_int = default (Int32);
882 | break;
883 |
884 | case JsonType.Long:
885 | inst_long = default (Int64);
886 | break;
887 |
888 | case JsonType.Double:
889 | inst_double = default (Double);
890 | break;
891 |
892 | case JsonType.Boolean:
893 | inst_boolean = default (Boolean);
894 | break;
895 | }
896 |
897 | this.type = type;
898 | }
899 |
900 | public string ToJson ()
901 | {
902 | if (json != null)
903 | return json;
904 |
905 | StringWriter sw = new StringWriter ();
906 | JsonWriter writer = new JsonWriter (sw);
907 | writer.Validate = false;
908 |
909 | WriteJson (this, writer);
910 | json = sw.ToString ();
911 |
912 | return json;
913 | }
914 |
915 | public void ToJson (JsonWriter writer)
916 | {
917 | bool old_validate = writer.Validate;
918 |
919 | writer.Validate = false;
920 |
921 | WriteJson (this, writer);
922 |
923 | writer.Validate = old_validate;
924 | }
925 |
926 | public override string ToString ()
927 | {
928 | switch (type) {
929 | case JsonType.Array:
930 | return "JsonData array";
931 |
932 | case JsonType.Boolean:
933 | return inst_boolean.ToString ();
934 |
935 | case JsonType.Double:
936 | return inst_double.ToString ();
937 |
938 | case JsonType.Int:
939 | return inst_int.ToString ();
940 |
941 | case JsonType.Long:
942 | return inst_long.ToString ();
943 |
944 | case JsonType.Object:
945 | return "JsonData object";
946 |
947 | case JsonType.String:
948 | return inst_string;
949 | }
950 |
951 | return "Uninitialized JsonData";
952 | }
953 | }
954 |
955 |
956 | internal class OrderedDictionaryEnumerator : IDictionaryEnumerator
957 | {
958 | IEnumerator> list_enumerator;
959 |
960 |
961 | public object Current {
962 | get { return Entry; }
963 | }
964 |
965 | public DictionaryEntry Entry {
966 | get {
967 | KeyValuePair curr = list_enumerator.Current;
968 | return new DictionaryEntry (curr.Key, curr.Value);
969 | }
970 | }
971 |
972 | public object Key {
973 | get { return list_enumerator.Current.Key; }
974 | }
975 |
976 | public object Value {
977 | get { return list_enumerator.Current.Value; }
978 | }
979 |
980 |
981 | public OrderedDictionaryEnumerator (
982 | IEnumerator> enumerator)
983 | {
984 | list_enumerator = enumerator;
985 | }
986 |
987 |
988 | public bool MoveNext ()
989 | {
990 | return list_enumerator.MoveNext ();
991 | }
992 |
993 | public void Reset ()
994 | {
995 | list_enumerator.Reset ();
996 | }
997 | }
998 | }
999 |
--------------------------------------------------------------------------------
/Scripts/UOJS/UOJS/LitJson/JsonException.cs:
--------------------------------------------------------------------------------
1 | #region Header
2 | /**
3 | * JsonException.cs
4 | * Base class throwed by LitJSON when a parsing error occurs.
5 | *
6 | * The authors disclaim copyright to this source code. For more details, see
7 | * the COPYING file included with this distribution.
8 | **/
9 | #endregion
10 |
11 |
12 | using System;
13 |
14 |
15 | namespace LitJson
16 | {
17 | public class JsonException : ApplicationException
18 | {
19 | public JsonException () : base ()
20 | {
21 | }
22 |
23 | internal JsonException (ParserToken token) :
24 | base (String.Format (
25 | "Invalid token '{0}' in input string", token))
26 | {
27 | }
28 |
29 | internal JsonException (ParserToken token,
30 | Exception inner_exception) :
31 | base (String.Format (
32 | "Invalid token '{0}' in input string", token),
33 | inner_exception)
34 | {
35 | }
36 |
37 | internal JsonException (int c) :
38 | base (String.Format (
39 | "Invalid character '{0}' in input string", (char) c))
40 | {
41 | }
42 |
43 | internal JsonException (int c, Exception inner_exception) :
44 | base (String.Format (
45 | "Invalid character '{0}' in input string", (char) c),
46 | inner_exception)
47 | {
48 | }
49 |
50 |
51 | public JsonException (string message) : base (message)
52 | {
53 | }
54 |
55 | public JsonException (string message, Exception inner_exception) :
56 | base (message, inner_exception)
57 | {
58 | }
59 | }
60 | }
61 |
--------------------------------------------------------------------------------
/Scripts/UOJS/UOJS/LitJson/JsonMapper.cs:
--------------------------------------------------------------------------------
1 | #region Header
2 | /**
3 | * JsonMapper.cs
4 | * JSON to .Net object and object to JSON conversions.
5 | *
6 | * The authors disclaim copyright to this source code. For more details, see
7 | * the COPYING file included with this distribution.
8 | **/
9 | #endregion
10 |
11 |
12 | using System;
13 | using System.Collections;
14 | using System.Collections.Generic;
15 | using System.Globalization;
16 | using System.IO;
17 | using System.Reflection;
18 |
19 |
20 | namespace LitJson
21 | {
22 | internal struct PropertyMetadata
23 | {
24 | public MemberInfo Info;
25 | public bool IsField;
26 | public Type Type;
27 | }
28 |
29 |
30 | internal struct ArrayMetadata
31 | {
32 | private Type element_type;
33 | private bool is_array;
34 | private bool is_list;
35 |
36 |
37 | public Type ElementType {
38 | get {
39 | if (element_type == null)
40 | return typeof (JsonData);
41 |
42 | return element_type;
43 | }
44 |
45 | set { element_type = value; }
46 | }
47 |
48 | public bool IsArray {
49 | get { return is_array; }
50 | set { is_array = value; }
51 | }
52 |
53 | public bool IsList {
54 | get { return is_list; }
55 | set { is_list = value; }
56 | }
57 | }
58 |
59 |
60 | internal struct ObjectMetadata
61 | {
62 | private Type element_type;
63 | private bool is_dictionary;
64 |
65 | private IDictionary properties;
66 |
67 |
68 | public Type ElementType {
69 | get {
70 | if (element_type == null)
71 | return typeof (JsonData);
72 |
73 | return element_type;
74 | }
75 |
76 | set { element_type = value; }
77 | }
78 |
79 | public bool IsDictionary {
80 | get { return is_dictionary; }
81 | set { is_dictionary = value; }
82 | }
83 |
84 | public IDictionary Properties {
85 | get { return properties; }
86 | set { properties = value; }
87 | }
88 | }
89 |
90 |
91 | internal delegate void ExporterFunc (object obj, JsonWriter writer);
92 | public delegate void ExporterFunc (T obj, JsonWriter writer);
93 |
94 | internal delegate object ImporterFunc (object input);
95 | public delegate TValue ImporterFunc (TJson input);
96 |
97 | public delegate IJsonWrapper WrapperFactory ();
98 |
99 |
100 | public class JsonMapper
101 | {
102 | #region Fields
103 | private static int max_nesting_depth;
104 |
105 | private static IFormatProvider datetime_format;
106 |
107 | private static IDictionary base_exporters_table;
108 | private static IDictionary custom_exporters_table;
109 |
110 | private static IDictionary> base_importers_table;
112 | private static IDictionary> custom_importers_table;
114 |
115 | private static IDictionary array_metadata;
116 | private static readonly object array_metadata_lock = new Object ();
117 |
118 | private static IDictionary> conv_ops;
120 | private static readonly object conv_ops_lock = new Object ();
121 |
122 | private static IDictionary object_metadata;
123 | private static readonly object object_metadata_lock = new Object ();
124 |
125 | private static IDictionary> type_properties;
127 | private static readonly object type_properties_lock = new Object ();
128 |
129 | private static JsonWriter static_writer;
130 | private static readonly object static_writer_lock = new Object ();
131 | #endregion
132 |
133 |
134 | #region Constructors
135 | static JsonMapper ()
136 | {
137 | max_nesting_depth = 100;
138 |
139 | array_metadata = new Dictionary ();
140 | conv_ops = new Dictionary> ();
141 | object_metadata = new Dictionary ();
142 | type_properties = new Dictionary> ();
144 |
145 | static_writer = new JsonWriter ();
146 |
147 | datetime_format = DateTimeFormatInfo.InvariantInfo;
148 |
149 | base_exporters_table = new Dictionary ();
150 | custom_exporters_table = new Dictionary ();
151 |
152 | base_importers_table = new Dictionary> ();
154 | custom_importers_table = new Dictionary> ();
156 |
157 | RegisterBaseExporters ();
158 | RegisterBaseImporters ();
159 | }
160 | #endregion
161 |
162 |
163 | #region Private Methods
164 | private static void AddArrayMetadata (Type type)
165 | {
166 | if (array_metadata.ContainsKey (type))
167 | return;
168 |
169 | ArrayMetadata data = new ArrayMetadata ();
170 |
171 | data.IsArray = type.IsArray;
172 |
173 | if (type.GetInterface ("System.Collections.IList") != null)
174 | data.IsList = true;
175 |
176 | foreach (PropertyInfo p_info in type.GetProperties ()) {
177 | if (p_info.Name != "Item")
178 | continue;
179 |
180 | ParameterInfo[] parameters = p_info.GetIndexParameters ();
181 |
182 | if (parameters.Length != 1)
183 | continue;
184 |
185 | if (parameters[0].ParameterType == typeof (int))
186 | data.ElementType = p_info.PropertyType;
187 | }
188 |
189 | lock (array_metadata_lock) {
190 | try {
191 | array_metadata.Add (type, data);
192 | } catch (ArgumentException) {
193 | return;
194 | }
195 | }
196 | }
197 |
198 | private static void AddObjectMetadata (Type type)
199 | {
200 | if (object_metadata.ContainsKey (type))
201 | return;
202 |
203 | ObjectMetadata data = new ObjectMetadata ();
204 |
205 | if (type.GetInterface ("System.Collections.IDictionary") != null)
206 | data.IsDictionary = true;
207 |
208 | data.Properties = new Dictionary ();
209 |
210 | foreach (PropertyInfo p_info in type.GetProperties ()) {
211 | if (p_info.Name == "Item") {
212 | ParameterInfo[] parameters = p_info.GetIndexParameters ();
213 |
214 | if (parameters.Length != 1)
215 | continue;
216 |
217 | if (parameters[0].ParameterType == typeof (string))
218 | data.ElementType = p_info.PropertyType;
219 |
220 | continue;
221 | }
222 |
223 | PropertyMetadata p_data = new PropertyMetadata ();
224 | p_data.Info = p_info;
225 | p_data.Type = p_info.PropertyType;
226 |
227 | data.Properties.Add (p_info.Name, p_data);
228 | }
229 |
230 | foreach (FieldInfo f_info in type.GetFields ()) {
231 | PropertyMetadata p_data = new PropertyMetadata ();
232 | p_data.Info = f_info;
233 | p_data.IsField = true;
234 | p_data.Type = f_info.FieldType;
235 |
236 | data.Properties.Add (f_info.Name, p_data);
237 | }
238 |
239 | lock (object_metadata_lock) {
240 | try {
241 | object_metadata.Add (type, data);
242 | } catch (ArgumentException) {
243 | return;
244 | }
245 | }
246 | }
247 |
248 | private static void AddTypeProperties (Type type)
249 | {
250 | if (type_properties.ContainsKey (type))
251 | return;
252 |
253 | IList props = new List ();
254 |
255 | foreach (PropertyInfo p_info in type.GetProperties ()) {
256 | if (p_info.Name == "Item")
257 | continue;
258 |
259 | PropertyMetadata p_data = new PropertyMetadata ();
260 | p_data.Info = p_info;
261 | p_data.IsField = false;
262 | props.Add (p_data);
263 | }
264 |
265 | foreach (FieldInfo f_info in type.GetFields ()) {
266 | PropertyMetadata p_data = new PropertyMetadata ();
267 | p_data.Info = f_info;
268 | p_data.IsField = true;
269 |
270 | props.Add (p_data);
271 | }
272 |
273 | lock (type_properties_lock) {
274 | try {
275 | type_properties.Add (type, props);
276 | } catch (ArgumentException) {
277 | return;
278 | }
279 | }
280 | }
281 |
282 | private static MethodInfo GetConvOp (Type t1, Type t2)
283 | {
284 | lock (conv_ops_lock) {
285 | if (! conv_ops.ContainsKey (t1))
286 | conv_ops.Add (t1, new Dictionary ());
287 | }
288 |
289 | if (conv_ops[t1].ContainsKey (t2))
290 | return conv_ops[t1][t2];
291 |
292 | MethodInfo op = t1.GetMethod (
293 | "op_Implicit", new Type[] { t2 });
294 |
295 | lock (conv_ops_lock) {
296 | try {
297 | conv_ops[t1].Add (t2, op);
298 | } catch (ArgumentException) {
299 | return conv_ops[t1][t2];
300 | }
301 | }
302 |
303 | return op;
304 | }
305 |
306 | private static object ReadValue (Type inst_type, JsonReader reader)
307 | {
308 | reader.Read ();
309 |
310 | if (reader.Token == JsonToken.ArrayEnd)
311 | return null;
312 |
313 | if (reader.Token == JsonToken.Null) {
314 |
315 | if (! inst_type.IsClass)
316 | throw new JsonException (String.Format (
317 | "Can't assign null to an instance of type {0}",
318 | inst_type));
319 |
320 | return null;
321 | }
322 |
323 | if (reader.Token == JsonToken.Double ||
324 | reader.Token == JsonToken.Int ||
325 | reader.Token == JsonToken.Long ||
326 | reader.Token == JsonToken.String ||
327 | reader.Token == JsonToken.Boolean) {
328 |
329 | Type json_type = reader.Value.GetType ();
330 |
331 | if (inst_type.IsAssignableFrom (json_type))
332 | return reader.Value;
333 |
334 | // If there's a custom importer that fits, use it
335 | if (custom_importers_table.ContainsKey (json_type) &&
336 | custom_importers_table[json_type].ContainsKey (
337 | inst_type)) {
338 |
339 | ImporterFunc importer =
340 | custom_importers_table[json_type][inst_type];
341 |
342 | return importer (reader.Value);
343 | }
344 |
345 | // Maybe there's a base importer that works
346 | if (base_importers_table.ContainsKey (json_type) &&
347 | base_importers_table[json_type].ContainsKey (
348 | inst_type)) {
349 |
350 | ImporterFunc importer =
351 | base_importers_table[json_type][inst_type];
352 |
353 | return importer (reader.Value);
354 | }
355 |
356 | // Maybe it's an enum
357 | if (inst_type.IsEnum)
358 | return Enum.ToObject (inst_type, reader.Value);
359 |
360 | // Try using an implicit conversion operator
361 | MethodInfo conv_op = GetConvOp (inst_type, json_type);
362 |
363 | if (conv_op != null)
364 | return conv_op.Invoke (null,
365 | new object[] { reader.Value });
366 |
367 | // No luck
368 | throw new JsonException (String.Format (
369 | "Can't assign value '{0}' (type {1}) to type {2}",
370 | reader.Value, json_type, inst_type));
371 | }
372 |
373 | object instance = null;
374 |
375 | if (reader.Token == JsonToken.ArrayStart) {
376 |
377 | AddArrayMetadata (inst_type);
378 | ArrayMetadata t_data = array_metadata[inst_type];
379 |
380 | if (! t_data.IsArray && ! t_data.IsList)
381 | throw new JsonException (String.Format (
382 | "Type {0} can't act as an array",
383 | inst_type));
384 |
385 | IList list;
386 | Type elem_type;
387 |
388 | if (! t_data.IsArray) {
389 | list = (IList) Activator.CreateInstance (inst_type);
390 | elem_type = t_data.ElementType;
391 | } else {
392 | list = new ArrayList ();
393 | elem_type = inst_type.GetElementType ();
394 | }
395 |
396 | while (true) {
397 | object item = ReadValue (elem_type, reader);
398 | if (item == null && reader.Token == JsonToken.ArrayEnd)
399 | break;
400 |
401 | list.Add (item);
402 | }
403 |
404 | if (t_data.IsArray) {
405 | int n = list.Count;
406 | instance = Array.CreateInstance (elem_type, n);
407 |
408 | for (int i = 0; i < n; i++)
409 | ((Array) instance).SetValue (list[i], i);
410 | } else
411 | instance = list;
412 |
413 | } else if (reader.Token == JsonToken.ObjectStart) {
414 |
415 | AddObjectMetadata (inst_type);
416 | ObjectMetadata t_data = object_metadata[inst_type];
417 |
418 | instance = Activator.CreateInstance (inst_type);
419 |
420 | while (true) {
421 | reader.Read ();
422 |
423 | if (reader.Token == JsonToken.ObjectEnd)
424 | break;
425 |
426 | string property = (string) reader.Value;
427 |
428 | if (t_data.Properties.ContainsKey (property)) {
429 | PropertyMetadata prop_data =
430 | t_data.Properties[property];
431 |
432 | if (prop_data.IsField) {
433 | ((FieldInfo) prop_data.Info).SetValue (
434 | instance, ReadValue (prop_data.Type, reader));
435 | } else {
436 | PropertyInfo p_info =
437 | (PropertyInfo) prop_data.Info;
438 |
439 | if (p_info.CanWrite)
440 | p_info.SetValue (
441 | instance,
442 | ReadValue (prop_data.Type, reader),
443 | null);
444 | else
445 | ReadValue (prop_data.Type, reader);
446 | }
447 |
448 | } else {
449 | if (! t_data.IsDictionary) {
450 |
451 | if (! reader.SkipNonMembers) {
452 | throw new JsonException (String.Format (
453 | "The type {0} doesn't have the " +
454 | "property '{1}'",
455 | inst_type, property));
456 | } else {
457 | ReadSkip (reader);
458 | continue;
459 | }
460 | }
461 |
462 | ((IDictionary) instance).Add (
463 | property, ReadValue (
464 | t_data.ElementType, reader));
465 | }
466 |
467 | }
468 |
469 | }
470 |
471 | return instance;
472 | }
473 |
474 | private static IJsonWrapper ReadValue (WrapperFactory factory,
475 | JsonReader reader)
476 | {
477 | reader.Read ();
478 |
479 | if (reader.Token == JsonToken.ArrayEnd ||
480 | reader.Token == JsonToken.Null)
481 | return null;
482 |
483 | IJsonWrapper instance = factory ();
484 |
485 | if (reader.Token == JsonToken.String) {
486 | instance.SetString ((string) reader.Value);
487 | return instance;
488 | }
489 |
490 | if (reader.Token == JsonToken.Double) {
491 | instance.SetDouble ((double) reader.Value);
492 | return instance;
493 | }
494 |
495 | if (reader.Token == JsonToken.Int) {
496 | instance.SetInt ((int) reader.Value);
497 | return instance;
498 | }
499 |
500 | if (reader.Token == JsonToken.Long) {
501 | instance.SetLong ((long) reader.Value);
502 | return instance;
503 | }
504 |
505 | if (reader.Token == JsonToken.Boolean) {
506 | instance.SetBoolean ((bool) reader.Value);
507 | return instance;
508 | }
509 |
510 | if (reader.Token == JsonToken.ArrayStart) {
511 | instance.SetJsonType (JsonType.Array);
512 |
513 | while (true) {
514 | IJsonWrapper item = ReadValue (factory, reader);
515 | if (item == null && reader.Token == JsonToken.ArrayEnd)
516 | break;
517 |
518 | ((IList) instance).Add (item);
519 | }
520 | }
521 | else if (reader.Token == JsonToken.ObjectStart) {
522 | instance.SetJsonType (JsonType.Object);
523 |
524 | while (true) {
525 | reader.Read ();
526 |
527 | if (reader.Token == JsonToken.ObjectEnd)
528 | break;
529 |
530 | string property = (string) reader.Value;
531 |
532 | ((IDictionary) instance)[property] = ReadValue (
533 | factory, reader);
534 | }
535 |
536 | }
537 |
538 | return instance;
539 | }
540 |
541 | private static void ReadSkip (JsonReader reader)
542 | {
543 | ToWrapper (
544 | delegate { return new JsonMockWrapper (); }, reader);
545 | }
546 |
547 | private static void RegisterBaseExporters ()
548 | {
549 | base_exporters_table[typeof (byte)] =
550 | delegate (object obj, JsonWriter writer) {
551 | writer.Write (Convert.ToInt32 ((byte) obj));
552 | };
553 |
554 | base_exporters_table[typeof (char)] =
555 | delegate (object obj, JsonWriter writer) {
556 | writer.Write (Convert.ToString ((char) obj));
557 | };
558 |
559 | base_exporters_table[typeof (DateTime)] =
560 | delegate (object obj, JsonWriter writer) {
561 | writer.Write (Convert.ToString ((DateTime) obj,
562 | datetime_format));
563 | };
564 |
565 | base_exporters_table[typeof (decimal)] =
566 | delegate (object obj, JsonWriter writer) {
567 | writer.Write ((decimal) obj);
568 | };
569 |
570 | base_exporters_table[typeof (sbyte)] =
571 | delegate (object obj, JsonWriter writer) {
572 | writer.Write (Convert.ToInt32 ((sbyte) obj));
573 | };
574 |
575 | base_exporters_table[typeof (short)] =
576 | delegate (object obj, JsonWriter writer) {
577 | writer.Write (Convert.ToInt32 ((short) obj));
578 | };
579 |
580 | base_exporters_table[typeof (ushort)] =
581 | delegate (object obj, JsonWriter writer) {
582 | writer.Write (Convert.ToInt32 ((ushort) obj));
583 | };
584 |
585 | base_exporters_table[typeof (uint)] =
586 | delegate (object obj, JsonWriter writer) {
587 | writer.Write (Convert.ToUInt64 ((uint) obj));
588 | };
589 |
590 | base_exporters_table[typeof (ulong)] =
591 | delegate (object obj, JsonWriter writer) {
592 | writer.Write ((ulong) obj);
593 | };
594 | }
595 |
596 | private static void RegisterBaseImporters ()
597 | {
598 | ImporterFunc importer;
599 |
600 | importer = delegate (object input) {
601 | return Convert.ToByte ((int) input);
602 | };
603 | RegisterImporter (base_importers_table, typeof (int),
604 | typeof (byte), importer);
605 |
606 | importer = delegate (object input) {
607 | return Convert.ToUInt64 ((int) input);
608 | };
609 | RegisterImporter (base_importers_table, typeof (int),
610 | typeof (ulong), importer);
611 |
612 | importer = delegate (object input) {
613 | return Convert.ToSByte ((int) input);
614 | };
615 | RegisterImporter (base_importers_table, typeof (int),
616 | typeof (sbyte), importer);
617 |
618 | importer = delegate (object input) {
619 | return Convert.ToInt16 ((int) input);
620 | };
621 | RegisterImporter (base_importers_table, typeof (int),
622 | typeof (short), importer);
623 |
624 | importer = delegate (object input) {
625 | return Convert.ToUInt16 ((int) input);
626 | };
627 | RegisterImporter (base_importers_table, typeof (int),
628 | typeof (ushort), importer);
629 |
630 | importer = delegate (object input) {
631 | return Convert.ToUInt32 ((int) input);
632 | };
633 | RegisterImporter (base_importers_table, typeof (int),
634 | typeof (uint), importer);
635 |
636 | importer = delegate (object input) {
637 | return Convert.ToSingle ((int) input);
638 | };
639 | RegisterImporter (base_importers_table, typeof (int),
640 | typeof (float), importer);
641 |
642 | importer = delegate (object input) {
643 | return Convert.ToDouble ((int) input);
644 | };
645 | RegisterImporter (base_importers_table, typeof (int),
646 | typeof (double), importer);
647 |
648 | importer = delegate (object input) {
649 | return Convert.ToDecimal ((double) input);
650 | };
651 | RegisterImporter (base_importers_table, typeof (double),
652 | typeof (decimal), importer);
653 |
654 |
655 | importer = delegate (object input) {
656 | return Convert.ToUInt32 ((long) input);
657 | };
658 | RegisterImporter (base_importers_table, typeof (long),
659 | typeof (uint), importer);
660 |
661 | importer = delegate (object input) {
662 | return Convert.ToChar ((string) input);
663 | };
664 | RegisterImporter (base_importers_table, typeof (string),
665 | typeof (char), importer);
666 |
667 | importer = delegate (object input) {
668 | return Convert.ToDateTime ((string) input, datetime_format);
669 | };
670 | RegisterImporter (base_importers_table, typeof (string),
671 | typeof (DateTime), importer);
672 | }
673 |
674 | private static void RegisterImporter (
675 | IDictionary> table,
676 | Type json_type, Type value_type, ImporterFunc importer)
677 | {
678 | if (! table.ContainsKey (json_type))
679 | table.Add (json_type, new Dictionary ());
680 |
681 | table[json_type][value_type] = importer;
682 | }
683 |
684 | private static void WriteValue (object obj, JsonWriter writer,
685 | bool writer_is_private,
686 | int depth)
687 | {
688 | if (depth > max_nesting_depth)
689 | throw new JsonException (
690 | String.Format ("Max allowed object depth reached while " +
691 | "trying to export from type {0}",
692 | obj.GetType ()));
693 |
694 | if (obj == null) {
695 | writer.Write (null);
696 | return;
697 | }
698 |
699 | if (obj is IJsonWrapper) {
700 | if (writer_is_private)
701 | writer.TextWriter.Write (((IJsonWrapper) obj).ToJson ());
702 | else
703 | ((IJsonWrapper) obj).ToJson (writer);
704 |
705 | return;
706 | }
707 |
708 | if (obj is String) {
709 | writer.Write ((string) obj);
710 | return;
711 | }
712 |
713 | if (obj is Double) {
714 | writer.Write ((double) obj);
715 | return;
716 | }
717 |
718 | if (obj is Int32) {
719 | writer.Write ((int) obj);
720 | return;
721 | }
722 |
723 | if (obj is Boolean) {
724 | writer.Write ((bool) obj);
725 | return;
726 | }
727 |
728 | if (obj is Int64) {
729 | writer.Write ((long) obj);
730 | return;
731 | }
732 |
733 | if (obj is Array) {
734 | writer.WriteArrayStart ();
735 |
736 | foreach (object elem in (Array) obj)
737 | WriteValue (elem, writer, writer_is_private, depth + 1);
738 |
739 | writer.WriteArrayEnd ();
740 |
741 | return;
742 | }
743 |
744 | if (obj is IList) {
745 | writer.WriteArrayStart ();
746 | foreach (object elem in (IList) obj)
747 | WriteValue (elem, writer, writer_is_private, depth + 1);
748 | writer.WriteArrayEnd ();
749 |
750 | return;
751 | }
752 |
753 | if (obj is IDictionary) {
754 | writer.WriteObjectStart ();
755 | foreach (DictionaryEntry entry in (IDictionary) obj) {
756 | writer.WritePropertyName ((string) entry.Key);
757 | WriteValue (entry.Value, writer, writer_is_private,
758 | depth + 1);
759 | }
760 | writer.WriteObjectEnd ();
761 |
762 | return;
763 | }
764 |
765 | Type obj_type = obj.GetType ();
766 |
767 | // See if there's a custom exporter for the object
768 | if (custom_exporters_table.ContainsKey (obj_type)) {
769 | ExporterFunc exporter = custom_exporters_table[obj_type];
770 | exporter (obj, writer);
771 |
772 | return;
773 | }
774 |
775 | // If not, maybe there's a base exporter
776 | if (base_exporters_table.ContainsKey (obj_type)) {
777 | ExporterFunc exporter = base_exporters_table[obj_type];
778 | exporter (obj, writer);
779 |
780 | return;
781 | }
782 |
783 | // Last option, let's see if it's an enum
784 | if (obj is Enum) {
785 | Type e_type = Enum.GetUnderlyingType (obj_type);
786 |
787 | if (e_type == typeof (long)
788 | || e_type == typeof (uint)
789 | || e_type == typeof (ulong))
790 | writer.Write ((ulong) obj);
791 | else
792 | writer.Write ((int) obj);
793 |
794 | return;
795 | }
796 |
797 | // Okay, so it looks like the input should be exported as an
798 | // object
799 | AddTypeProperties (obj_type);
800 | IList props = type_properties[obj_type];
801 |
802 | writer.WriteObjectStart ();
803 | foreach (PropertyMetadata p_data in props) {
804 | if (p_data.IsField) {
805 | writer.WritePropertyName (p_data.Info.Name);
806 | WriteValue (((FieldInfo) p_data.Info).GetValue (obj),
807 | writer, writer_is_private, depth + 1);
808 | }
809 | else {
810 | PropertyInfo p_info = (PropertyInfo) p_data.Info;
811 |
812 | if (p_info.CanRead) {
813 | writer.WritePropertyName (p_data.Info.Name);
814 | WriteValue (p_info.GetValue (obj, null),
815 | writer, writer_is_private, depth + 1);
816 | }
817 | }
818 | }
819 | writer.WriteObjectEnd ();
820 | }
821 | #endregion
822 |
823 |
824 | public static string ToJson (object obj)
825 | {
826 | lock (static_writer_lock) {
827 | static_writer.Reset ();
828 |
829 | WriteValue (obj, static_writer, true, 0);
830 |
831 | return static_writer.ToString ();
832 | }
833 | }
834 |
835 | public static void ToJson (object obj, JsonWriter writer)
836 | {
837 | WriteValue (obj, writer, false, 0);
838 | }
839 |
840 | public static JsonData ToObject (JsonReader reader)
841 | {
842 | return (JsonData) ToWrapper (
843 | delegate { return new JsonData (); }, reader);
844 | }
845 |
846 | public static JsonData ToObject (TextReader reader)
847 | {
848 | JsonReader json_reader = new JsonReader (reader);
849 |
850 | return (JsonData) ToWrapper (
851 | delegate { return new JsonData (); }, json_reader);
852 | }
853 |
854 | public static JsonData ToObject (string json)
855 | {
856 | return (JsonData) ToWrapper (
857 | delegate { return new JsonData (); }, json);
858 | }
859 |
860 | public static T ToObject (JsonReader reader)
861 | {
862 | return (T) ReadValue (typeof (T), reader);
863 | }
864 |
865 | public static T ToObject (TextReader reader)
866 | {
867 | JsonReader json_reader = new JsonReader (reader);
868 |
869 | return (T) ReadValue (typeof (T), json_reader);
870 | }
871 |
872 | public static T ToObject (string json)
873 | {
874 | JsonReader reader = new JsonReader (json);
875 |
876 | return (T) ReadValue (typeof (T), reader);
877 | }
878 |
879 | public static IJsonWrapper ToWrapper (WrapperFactory factory,
880 | JsonReader reader)
881 | {
882 | return ReadValue (factory, reader);
883 | }
884 |
885 | public static IJsonWrapper ToWrapper (WrapperFactory factory,
886 | string json)
887 | {
888 | JsonReader reader = new JsonReader (json);
889 |
890 | return ReadValue (factory, reader);
891 | }
892 |
893 | public static void RegisterExporter (ExporterFunc exporter)
894 | {
895 | ExporterFunc exporter_wrapper =
896 | delegate (object obj, JsonWriter writer) {
897 | exporter ((T) obj, writer);
898 | };
899 |
900 | custom_exporters_table[typeof (T)] = exporter_wrapper;
901 | }
902 |
903 | public static void RegisterImporter (
904 | ImporterFunc importer)
905 | {
906 | ImporterFunc importer_wrapper =
907 | delegate (object input) {
908 | return importer ((TJson) input);
909 | };
910 |
911 | RegisterImporter (custom_importers_table, typeof (TJson),
912 | typeof (TValue), importer_wrapper);
913 | }
914 |
915 | public static void UnregisterExporters ()
916 | {
917 | custom_exporters_table.Clear ();
918 | }
919 |
920 | public static void UnregisterImporters ()
921 | {
922 | custom_importers_table.Clear ();
923 | }
924 | }
925 | }
926 |
--------------------------------------------------------------------------------
/Scripts/UOJS/UOJS/LitJson/JsonMockWrapper.cs:
--------------------------------------------------------------------------------
1 | #region Header
2 | /**
3 | * JsonMockWrapper.cs
4 | * Mock object implementing IJsonWrapper, to facilitate actions like
5 | * skipping data more efficiently.
6 | *
7 | * The authors disclaim copyright to this source code. For more details, see
8 | * the COPYING file included with this distribution.
9 | **/
10 | #endregion
11 |
12 |
13 | using System;
14 | using System.Collections;
15 | using System.Collections.Specialized;
16 |
17 |
18 | namespace LitJson
19 | {
20 | public class JsonMockWrapper : IJsonWrapper
21 | {
22 | public bool IsArray { get { return false; } }
23 | public bool IsBoolean { get { return false; } }
24 | public bool IsDouble { get { return false; } }
25 | public bool IsInt { get { return false; } }
26 | public bool IsLong { get { return false; } }
27 | public bool IsObject { get { return false; } }
28 | public bool IsString { get { return false; } }
29 |
30 | public bool GetBoolean () { return false; }
31 | public double GetDouble () { return 0.0; }
32 | public int GetInt () { return 0; }
33 | public JsonType GetJsonType () { return JsonType.None; }
34 | public long GetLong () { return 0L; }
35 | public string GetString () { return ""; }
36 |
37 | public void SetBoolean (bool val) {}
38 | public void SetDouble (double val) {}
39 | public void SetInt (int val) {}
40 | public void SetJsonType (JsonType type) {}
41 | public void SetLong (long val) {}
42 | public void SetString (string val) {}
43 |
44 | public string ToJson () { return ""; }
45 | public void ToJson (JsonWriter writer) {}
46 |
47 |
48 | bool IList.IsFixedSize { get { return true; } }
49 | bool IList.IsReadOnly { get { return true; } }
50 |
51 | object IList.this[int index] {
52 | get { return null; }
53 | set {}
54 | }
55 |
56 | int IList.Add (object value) { return 0; }
57 | void IList.Clear () {}
58 | bool IList.Contains (object value) { return false; }
59 | int IList.IndexOf (object value) { return -1; }
60 | void IList.Insert (int i, object v) {}
61 | void IList.Remove (object value) {}
62 | void IList.RemoveAt (int index) {}
63 |
64 |
65 | int ICollection.Count { get { return 0; } }
66 | bool ICollection.IsSynchronized { get { return false; } }
67 | object ICollection.SyncRoot { get { return null; } }
68 |
69 | void ICollection.CopyTo (Array array, int index) {}
70 |
71 |
72 | IEnumerator IEnumerable.GetEnumerator () { return null; }
73 |
74 |
75 | bool IDictionary.IsFixedSize { get { return true; } }
76 | bool IDictionary.IsReadOnly { get { return true; } }
77 |
78 | ICollection IDictionary.Keys { get { return null; } }
79 | ICollection IDictionary.Values { get { return null; } }
80 |
81 | object IDictionary.this[object key] {
82 | get { return null; }
83 | set {}
84 | }
85 |
86 | void IDictionary.Add (object k, object v) {}
87 | void IDictionary.Clear () {}
88 | bool IDictionary.Contains (object key) { return false; }
89 | void IDictionary.Remove (object key) {}
90 |
91 | IDictionaryEnumerator IDictionary.GetEnumerator () { return null; }
92 |
93 |
94 | object IOrderedDictionary.this[int idx] {
95 | get { return null; }
96 | set {}
97 | }
98 |
99 | IDictionaryEnumerator IOrderedDictionary.GetEnumerator () {
100 | return null;
101 | }
102 | void IOrderedDictionary.Insert (int i, object k, object v) {}
103 | void IOrderedDictionary.RemoveAt (int i) {}
104 | }
105 | }
106 |
--------------------------------------------------------------------------------
/Scripts/UOJS/UOJS/LitJson/JsonReader.cs:
--------------------------------------------------------------------------------
1 | #region Header
2 | /**
3 | * JsonReader.cs
4 | * Stream-like access to JSON text.
5 | *
6 | * The authors disclaim copyright to this source code. For more details, see
7 | * the COPYING file included with this distribution.
8 | **/
9 | #endregion
10 |
11 |
12 | using System;
13 | using System.Collections.Generic;
14 | using System.IO;
15 | using System.Text;
16 |
17 |
18 | namespace LitJson
19 | {
20 | public enum JsonToken
21 | {
22 | None,
23 |
24 | ObjectStart,
25 | PropertyName,
26 | ObjectEnd,
27 |
28 | ArrayStart,
29 | ArrayEnd,
30 |
31 | Int,
32 | Long,
33 | Double,
34 |
35 | String,
36 |
37 | Boolean,
38 | Null
39 | }
40 |
41 |
42 | public class JsonReader
43 | {
44 | #region Fields
45 | private static IDictionary> parse_table;
46 |
47 | private Stack automaton_stack;
48 | private int current_input;
49 | private int current_symbol;
50 | private bool end_of_json;
51 | private bool end_of_input;
52 | private Lexer lexer;
53 | private bool parser_in_string;
54 | private bool parser_return;
55 | private bool read_started;
56 | private TextReader reader;
57 | private bool reader_is_owned;
58 | private bool skip_non_members;
59 | private object token_value;
60 | private JsonToken token;
61 | #endregion
62 |
63 |
64 | #region Public Properties
65 | public bool AllowComments {
66 | get { return lexer.AllowComments; }
67 | set { lexer.AllowComments = value; }
68 | }
69 |
70 | public bool AllowSingleQuotedStrings {
71 | get { return lexer.AllowSingleQuotedStrings; }
72 | set { lexer.AllowSingleQuotedStrings = value; }
73 | }
74 |
75 | public bool SkipNonMembers {
76 | get { return skip_non_members; }
77 | set { skip_non_members = value; }
78 | }
79 |
80 | public bool EndOfInput {
81 | get { return end_of_input; }
82 | }
83 |
84 | public bool EndOfJson {
85 | get { return end_of_json; }
86 | }
87 |
88 | public JsonToken Token {
89 | get { return token; }
90 | }
91 |
92 | public object Value {
93 | get { return token_value; }
94 | }
95 | #endregion
96 |
97 |
98 | #region Constructors
99 | static JsonReader ()
100 | {
101 | PopulateParseTable ();
102 | }
103 |
104 | public JsonReader (string json_text) :
105 | this (new StringReader (json_text), true)
106 | {
107 | }
108 |
109 | public JsonReader (TextReader reader) :
110 | this (reader, false)
111 | {
112 | }
113 |
114 | private JsonReader (TextReader reader, bool owned)
115 | {
116 | if (reader == null)
117 | throw new ArgumentNullException ("reader");
118 |
119 | parser_in_string = false;
120 | parser_return = false;
121 |
122 | read_started = false;
123 | automaton_stack = new Stack ();
124 | automaton_stack.Push ((int) ParserToken.End);
125 | automaton_stack.Push ((int) ParserToken.Text);
126 |
127 | lexer = new Lexer (reader);
128 |
129 | end_of_input = false;
130 | end_of_json = false;
131 |
132 | skip_non_members = true;
133 |
134 | this.reader = reader;
135 | reader_is_owned = owned;
136 | }
137 | #endregion
138 |
139 |
140 | #region Static Methods
141 | private static void PopulateParseTable ()
142 | {
143 | // See section A.2. of the manual for details
144 | parse_table = new Dictionary> ();
145 |
146 | TableAddRow (ParserToken.Array);
147 | TableAddCol (ParserToken.Array, '[',
148 | '[',
149 | (int) ParserToken.ArrayPrime);
150 |
151 | TableAddRow (ParserToken.ArrayPrime);
152 | TableAddCol (ParserToken.ArrayPrime, '"',
153 | (int) ParserToken.Value,
154 |
155 | (int) ParserToken.ValueRest,
156 | ']');
157 | TableAddCol (ParserToken.ArrayPrime, '[',
158 | (int) ParserToken.Value,
159 | (int) ParserToken.ValueRest,
160 | ']');
161 | TableAddCol (ParserToken.ArrayPrime, ']',
162 | ']');
163 | TableAddCol (ParserToken.ArrayPrime, '{',
164 | (int) ParserToken.Value,
165 | (int) ParserToken.ValueRest,
166 | ']');
167 | TableAddCol (ParserToken.ArrayPrime, (int) ParserToken.Number,
168 | (int) ParserToken.Value,
169 | (int) ParserToken.ValueRest,
170 | ']');
171 | TableAddCol (ParserToken.ArrayPrime, (int) ParserToken.True,
172 | (int) ParserToken.Value,
173 | (int) ParserToken.ValueRest,
174 | ']');
175 | TableAddCol (ParserToken.ArrayPrime, (int) ParserToken.False,
176 | (int) ParserToken.Value,
177 | (int) ParserToken.ValueRest,
178 | ']');
179 | TableAddCol (ParserToken.ArrayPrime, (int) ParserToken.Null,
180 | (int) ParserToken.Value,
181 | (int) ParserToken.ValueRest,
182 | ']');
183 |
184 | TableAddRow (ParserToken.Object);
185 | TableAddCol (ParserToken.Object, '{',
186 | '{',
187 | (int) ParserToken.ObjectPrime);
188 |
189 | TableAddRow (ParserToken.ObjectPrime);
190 | TableAddCol (ParserToken.ObjectPrime, '"',
191 | (int) ParserToken.Pair,
192 | (int) ParserToken.PairRest,
193 | '}');
194 | TableAddCol (ParserToken.ObjectPrime, '}',
195 | '}');
196 |
197 | TableAddRow (ParserToken.Pair);
198 | TableAddCol (ParserToken.Pair, '"',
199 | (int) ParserToken.String,
200 | ':',
201 | (int) ParserToken.Value);
202 |
203 | TableAddRow (ParserToken.PairRest);
204 | TableAddCol (ParserToken.PairRest, ',',
205 | ',',
206 | (int) ParserToken.Pair,
207 | (int) ParserToken.PairRest);
208 | TableAddCol (ParserToken.PairRest, '}',
209 | (int) ParserToken.Epsilon);
210 |
211 | TableAddRow (ParserToken.String);
212 | TableAddCol (ParserToken.String, '"',
213 | '"',
214 | (int) ParserToken.CharSeq,
215 | '"');
216 |
217 | TableAddRow (ParserToken.Text);
218 | TableAddCol (ParserToken.Text, '[',
219 | (int) ParserToken.Array);
220 | TableAddCol (ParserToken.Text, '{',
221 | (int) ParserToken.Object);
222 |
223 | TableAddRow (ParserToken.Value);
224 | TableAddCol (ParserToken.Value, '"',
225 | (int) ParserToken.String);
226 | TableAddCol (ParserToken.Value, '[',
227 | (int) ParserToken.Array);
228 | TableAddCol (ParserToken.Value, '{',
229 | (int) ParserToken.Object);
230 | TableAddCol (ParserToken.Value, (int) ParserToken.Number,
231 | (int) ParserToken.Number);
232 | TableAddCol (ParserToken.Value, (int) ParserToken.True,
233 | (int) ParserToken.True);
234 | TableAddCol (ParserToken.Value, (int) ParserToken.False,
235 | (int) ParserToken.False);
236 | TableAddCol (ParserToken.Value, (int) ParserToken.Null,
237 | (int) ParserToken.Null);
238 |
239 | TableAddRow (ParserToken.ValueRest);
240 | TableAddCol (ParserToken.ValueRest, ',',
241 | ',',
242 | (int) ParserToken.Value,
243 | (int) ParserToken.ValueRest);
244 | TableAddCol (ParserToken.ValueRest, ']',
245 | (int) ParserToken.Epsilon);
246 | }
247 |
248 | private static void TableAddCol (ParserToken row, int col,
249 | params int[] symbols)
250 | {
251 | parse_table[(int) row].Add (col, symbols);
252 | }
253 |
254 | private static void TableAddRow (ParserToken rule)
255 | {
256 | parse_table.Add ((int) rule, new Dictionary ());
257 | }
258 | #endregion
259 |
260 |
261 | #region Private Methods
262 | private void ProcessNumber (string number)
263 | {
264 | if (number.IndexOf ('.') != -1 ||
265 | number.IndexOf ('e') != -1 ||
266 | number.IndexOf ('E') != -1) {
267 |
268 | double n_double;
269 | if (Double.TryParse (number, out n_double)) {
270 | token = JsonToken.Double;
271 | token_value = n_double;
272 |
273 | return;
274 | }
275 | }
276 |
277 | int n_int32;
278 | if (Int32.TryParse (number, out n_int32)) {
279 | token = JsonToken.Int;
280 | token_value = n_int32;
281 |
282 | return;
283 | }
284 |
285 | long n_int64;
286 | if (Int64.TryParse (number, out n_int64)) {
287 | token = JsonToken.Long;
288 | token_value = n_int64;
289 |
290 | return;
291 | }
292 |
293 | // Shouldn't happen, but just in case, return something
294 | token = JsonToken.Int;
295 | token_value = 0;
296 | }
297 |
298 | private void ProcessSymbol ()
299 | {
300 | if (current_symbol == '[') {
301 | token = JsonToken.ArrayStart;
302 | parser_return = true;
303 |
304 | } else if (current_symbol == ']') {
305 | token = JsonToken.ArrayEnd;
306 | parser_return = true;
307 |
308 | } else if (current_symbol == '{') {
309 | token = JsonToken.ObjectStart;
310 | parser_return = true;
311 |
312 | } else if (current_symbol == '}') {
313 | token = JsonToken.ObjectEnd;
314 | parser_return = true;
315 |
316 | } else if (current_symbol == '"') {
317 | if (parser_in_string) {
318 | parser_in_string = false;
319 |
320 | parser_return = true;
321 |
322 | } else {
323 | if (token == JsonToken.None)
324 | token = JsonToken.String;
325 |
326 | parser_in_string = true;
327 | }
328 |
329 | } else if (current_symbol == (int) ParserToken.CharSeq) {
330 | token_value = lexer.StringValue;
331 |
332 | } else if (current_symbol == (int) ParserToken.False) {
333 | token = JsonToken.Boolean;
334 | token_value = false;
335 | parser_return = true;
336 |
337 | } else if (current_symbol == (int) ParserToken.Null) {
338 | token = JsonToken.Null;
339 | parser_return = true;
340 |
341 | } else if (current_symbol == (int) ParserToken.Number) {
342 | ProcessNumber (lexer.StringValue);
343 |
344 | parser_return = true;
345 |
346 | } else if (current_symbol == (int) ParserToken.Pair) {
347 | token = JsonToken.PropertyName;
348 |
349 | } else if (current_symbol == (int) ParserToken.True) {
350 | token = JsonToken.Boolean;
351 | token_value = true;
352 | parser_return = true;
353 |
354 | }
355 | }
356 |
357 | private bool ReadToken ()
358 | {
359 | if (end_of_input)
360 | return false;
361 |
362 | lexer.NextToken ();
363 |
364 | if (lexer.EndOfInput) {
365 | Close ();
366 |
367 | return false;
368 | }
369 |
370 | current_input = lexer.Token;
371 |
372 | return true;
373 | }
374 | #endregion
375 |
376 |
377 | public void Close ()
378 | {
379 | if (end_of_input)
380 | return;
381 |
382 | end_of_input = true;
383 | end_of_json = true;
384 |
385 | if (reader_is_owned)
386 | reader.Close ();
387 |
388 | reader = null;
389 | }
390 |
391 | public bool Read ()
392 | {
393 | if (end_of_input)
394 | return false;
395 |
396 | if (end_of_json) {
397 | end_of_json = false;
398 | automaton_stack.Clear ();
399 | automaton_stack.Push ((int) ParserToken.End);
400 | automaton_stack.Push ((int) ParserToken.Text);
401 | }
402 |
403 | parser_in_string = false;
404 | parser_return = false;
405 |
406 | token = JsonToken.None;
407 | token_value = null;
408 |
409 | if (! read_started) {
410 | read_started = true;
411 |
412 | if (! ReadToken ())
413 | return false;
414 | }
415 |
416 |
417 | int[] entry_symbols;
418 |
419 | while (true) {
420 | if (parser_return) {
421 | if (automaton_stack.Peek () == (int) ParserToken.End)
422 | end_of_json = true;
423 |
424 | return true;
425 | }
426 |
427 | current_symbol = automaton_stack.Pop ();
428 |
429 | ProcessSymbol ();
430 |
431 | if (current_symbol == current_input) {
432 | if (! ReadToken ()) {
433 | if (automaton_stack.Peek () != (int) ParserToken.End)
434 | throw new JsonException (
435 | "Input doesn't evaluate to proper JSON text");
436 |
437 | if (parser_return)
438 | return true;
439 |
440 | return false;
441 | }
442 |
443 | continue;
444 | }
445 |
446 | try {
447 |
448 | entry_symbols =
449 | parse_table[current_symbol][current_input];
450 |
451 | } catch (KeyNotFoundException e) {
452 | throw new JsonException ((ParserToken) current_input, e);
453 | }
454 |
455 | if (entry_symbols[0] == (int) ParserToken.Epsilon)
456 | continue;
457 |
458 | for (int i = entry_symbols.Length - 1; i >= 0; i--)
459 | automaton_stack.Push (entry_symbols[i]);
460 | }
461 | }
462 |
463 | }
464 | }
465 |
--------------------------------------------------------------------------------
/Scripts/UOJS/UOJS/LitJson/JsonWriter.cs:
--------------------------------------------------------------------------------
1 | #region Header
2 | /**
3 | * JsonWriter.cs
4 | * Stream-like facility to output JSON text.
5 | *
6 | * The authors disclaim copyright to this source code. For more details, see
7 | * the COPYING file included with this distribution.
8 | **/
9 | #endregion
10 |
11 |
12 | using System;
13 | using System.Collections.Generic;
14 | using System.Globalization;
15 | using System.IO;
16 | using System.Text;
17 |
18 |
19 | namespace LitJson
20 | {
21 | internal enum Condition
22 | {
23 | InArray,
24 | InObject,
25 | NotAProperty,
26 | Property,
27 | Value
28 | }
29 |
30 | internal class WriterContext
31 | {
32 | public int Count;
33 | public bool InArray;
34 | public bool InObject;
35 | public bool ExpectingValue;
36 | public int Padding;
37 | }
38 |
39 | public class JsonWriter
40 | {
41 | #region Fields
42 | private static NumberFormatInfo number_format;
43 |
44 | private WriterContext context;
45 | private Stack ctx_stack;
46 | private bool has_reached_end;
47 | private char[] hex_seq;
48 | private int indentation;
49 | private int indent_value;
50 | private StringBuilder inst_string_builder;
51 | private bool pretty_print;
52 | private bool validate;
53 | private TextWriter writer;
54 | #endregion
55 |
56 |
57 | #region Properties
58 | public int IndentValue {
59 | get { return indent_value; }
60 | set {
61 | indentation = (indentation / indent_value) * value;
62 | indent_value = value;
63 | }
64 | }
65 |
66 | public bool PrettyPrint {
67 | get { return pretty_print; }
68 | set { pretty_print = value; }
69 | }
70 |
71 | public TextWriter TextWriter {
72 | get { return writer; }
73 | }
74 |
75 | public bool Validate {
76 | get { return validate; }
77 | set { validate = value; }
78 | }
79 | #endregion
80 |
81 |
82 | #region Constructors
83 | static JsonWriter ()
84 | {
85 | number_format = NumberFormatInfo.InvariantInfo;
86 | }
87 |
88 | public JsonWriter ()
89 | {
90 | inst_string_builder = new StringBuilder ();
91 | writer = new StringWriter (inst_string_builder);
92 |
93 | Init ();
94 | }
95 |
96 | public JsonWriter (StringBuilder sb) :
97 | this (new StringWriter (sb))
98 | {
99 | }
100 |
101 | public JsonWriter (TextWriter writer)
102 | {
103 | if (writer == null)
104 | throw new ArgumentNullException ("writer");
105 |
106 | this.writer = writer;
107 |
108 | Init ();
109 | }
110 | #endregion
111 |
112 |
113 | #region Private Methods
114 | private void DoValidation (Condition cond)
115 | {
116 | if (! context.ExpectingValue)
117 | context.Count++;
118 |
119 | if (! validate)
120 | return;
121 |
122 | if (has_reached_end)
123 | throw new JsonException (
124 | "A complete JSON symbol has already been written");
125 |
126 | switch (cond) {
127 | case Condition.InArray:
128 | if (! context.InArray)
129 | throw new JsonException (
130 | "Can't close an array here");
131 | break;
132 |
133 | case Condition.InObject:
134 | if (! context.InObject || context.ExpectingValue)
135 | throw new JsonException (
136 | "Can't close an object here");
137 | break;
138 |
139 | case Condition.NotAProperty:
140 | if (context.InObject && ! context.ExpectingValue)
141 | throw new JsonException (
142 | "Expected a property");
143 | break;
144 |
145 | case Condition.Property:
146 | if (! context.InObject || context.ExpectingValue)
147 | throw new JsonException (
148 | "Can't add a property here");
149 | break;
150 |
151 | case Condition.Value:
152 | if (! context.InArray &&
153 | (! context.InObject || ! context.ExpectingValue))
154 | throw new JsonException (
155 | "Can't add a value here");
156 |
157 | break;
158 | }
159 | }
160 |
161 | private void Init ()
162 | {
163 | has_reached_end = false;
164 | hex_seq = new char[4];
165 | indentation = 0;
166 | indent_value = 4;
167 | pretty_print = false;
168 | validate = true;
169 |
170 | ctx_stack = new Stack ();
171 | context = new WriterContext ();
172 | ctx_stack.Push (context);
173 | }
174 |
175 | private static void IntToHex (int n, char[] hex)
176 | {
177 | int num;
178 |
179 | for (int i = 0; i < 4; i++) {
180 | num = n % 16;
181 |
182 | if (num < 10)
183 | hex [3 - i] = (char)('0' + num);
184 | else
185 | hex [3 - i] = (char)('A' + (num - 10));
186 |
187 | n >>= 4;
188 | }
189 | }
190 |
191 | private void Indent ()
192 | {
193 | if (pretty_print)
194 | indentation += indent_value;
195 | }
196 |
197 |
198 | private void Put (string str)
199 | {
200 | if (pretty_print && ! context.ExpectingValue)
201 | for (int i = 0; i < indentation; i++)
202 | writer.Write (' ');
203 |
204 | writer.Write (str);
205 | }
206 |
207 | private void PutNewline ()
208 | {
209 | PutNewline (true);
210 | }
211 |
212 | private void PutNewline (bool add_comma)
213 | {
214 | if (add_comma && ! context.ExpectingValue &&
215 | context.Count > 1)
216 | writer.Write (',');
217 |
218 | if (pretty_print && ! context.ExpectingValue)
219 | writer.Write ('\n');
220 | }
221 |
222 | private void PutString (string str)
223 | {
224 | Put (String.Empty);
225 |
226 | writer.Write ('"');
227 |
228 | int n = str.Length;
229 | for (int i = 0; i < n; i++) {
230 | switch (str [i]) {
231 | case '\n':
232 | writer.Write ("\\n");
233 | continue;
234 |
235 | case '\r':
236 | writer.Write ("\\r");
237 | continue;
238 |
239 | case '\t':
240 | writer.Write ("\\t");
241 | continue;
242 |
243 | case '"':
244 | case '\\':
245 | writer.Write ('\\');
246 | writer.Write (str [i]);
247 | continue;
248 |
249 | case '\f':
250 | writer.Write ("\\f");
251 | continue;
252 |
253 | case '\b':
254 | writer.Write ("\\b");
255 | continue;
256 | }
257 |
258 | if ((int)str [i] >= 32 && (int)str [i] <= 126) {
259 | writer.Write (str [i]);
260 | continue;
261 | }
262 |
263 | // Default, turn into a \uXXXX sequence
264 | IntToHex ((int)str [i], hex_seq);
265 | writer.Write ("\\u");
266 | writer.Write (hex_seq);
267 | }
268 |
269 | writer.Write ('"');
270 | }
271 |
272 | private void Unindent ()
273 | {
274 | if (pretty_print)
275 | indentation -= indent_value;
276 | }
277 | #endregion
278 |
279 |
280 | public override string ToString ()
281 | {
282 | if (inst_string_builder == null)
283 | return String.Empty;
284 |
285 | return inst_string_builder.ToString ();
286 | }
287 |
288 | public void Reset ()
289 | {
290 | has_reached_end = false;
291 |
292 | ctx_stack.Clear ();
293 | context = new WriterContext ();
294 | ctx_stack.Push (context);
295 |
296 | if (inst_string_builder != null)
297 | inst_string_builder.Remove (0, inst_string_builder.Length);
298 | }
299 |
300 | public void Write (bool boolean)
301 | {
302 | DoValidation (Condition.Value);
303 | PutNewline ();
304 |
305 | Put (boolean ? "true" : "false");
306 |
307 | context.ExpectingValue = false;
308 | }
309 |
310 | public void Write (decimal number)
311 | {
312 | DoValidation (Condition.Value);
313 | PutNewline ();
314 |
315 | Put (Convert.ToString (number, number_format));
316 |
317 | context.ExpectingValue = false;
318 | }
319 |
320 | public void Write (double number)
321 | {
322 | DoValidation (Condition.Value);
323 | PutNewline ();
324 |
325 | string str = Convert.ToString (number, number_format);
326 | Put (str);
327 |
328 | if (str.IndexOf ('.') == -1 &&
329 | str.IndexOf ('E') == -1)
330 | writer.Write (".0");
331 |
332 | context.ExpectingValue = false;
333 | }
334 |
335 | public void Write (int number)
336 | {
337 | DoValidation (Condition.Value);
338 | PutNewline ();
339 |
340 | Put (Convert.ToString (number, number_format));
341 |
342 | context.ExpectingValue = false;
343 | }
344 |
345 | public void Write (long number)
346 | {
347 | DoValidation (Condition.Value);
348 | PutNewline ();
349 |
350 | Put (Convert.ToString (number, number_format));
351 |
352 | context.ExpectingValue = false;
353 | }
354 |
355 | public void Write (string str)
356 | {
357 | DoValidation (Condition.Value);
358 | PutNewline ();
359 |
360 | if (str == null)
361 | Put ("null");
362 | else
363 | PutString (str);
364 |
365 | context.ExpectingValue = false;
366 | }
367 |
368 | //[CLSCompliant(false)]
369 | public void Write (ulong number)
370 | {
371 | DoValidation (Condition.Value);
372 | PutNewline ();
373 |
374 | Put (Convert.ToString (number, number_format));
375 |
376 | context.ExpectingValue = false;
377 | }
378 |
379 | public void WriteArrayEnd ()
380 | {
381 | DoValidation (Condition.InArray);
382 | PutNewline (false);
383 |
384 | ctx_stack.Pop ();
385 | if (ctx_stack.Count == 1)
386 | has_reached_end = true;
387 | else {
388 | context = ctx_stack.Peek ();
389 | context.ExpectingValue = false;
390 | }
391 |
392 | Unindent ();
393 | Put ("]");
394 | }
395 |
396 | public void WriteArrayStart ()
397 | {
398 | DoValidation (Condition.NotAProperty);
399 | PutNewline ();
400 |
401 | Put ("[");
402 |
403 | context = new WriterContext ();
404 | context.InArray = true;
405 | ctx_stack.Push (context);
406 |
407 | Indent ();
408 | }
409 |
410 | public void WriteObjectEnd ()
411 | {
412 | DoValidation (Condition.InObject);
413 | PutNewline (false);
414 |
415 | ctx_stack.Pop ();
416 | if (ctx_stack.Count == 1)
417 | has_reached_end = true;
418 | else {
419 | context = ctx_stack.Peek ();
420 | context.ExpectingValue = false;
421 | }
422 |
423 | Unindent ();
424 | Put ("}");
425 | }
426 |
427 | public void WriteObjectStart ()
428 | {
429 | DoValidation (Condition.NotAProperty);
430 | PutNewline ();
431 |
432 | Put ("{");
433 |
434 | context = new WriterContext ();
435 | context.InObject = true;
436 | ctx_stack.Push (context);
437 |
438 | Indent ();
439 | }
440 |
441 | public void WritePropertyName (string property_name)
442 | {
443 | DoValidation (Condition.Property);
444 | PutNewline ();
445 |
446 | PutString (property_name);
447 |
448 | if (pretty_print) {
449 | if (property_name.Length > context.Padding)
450 | context.Padding = property_name.Length;
451 |
452 | for (int i = context.Padding - property_name.Length;
453 | i >= 0; i--)
454 | writer.Write (' ');
455 |
456 | writer.Write (": ");
457 | } else
458 | writer.Write (':');
459 |
460 | context.ExpectingValue = true;
461 | }
462 | }
463 | }
464 |
--------------------------------------------------------------------------------
/Scripts/UOJS/UOJS/LitJson/Lexer.cs:
--------------------------------------------------------------------------------
1 | #region Header
2 | /**
3 | * Lexer.cs
4 | * JSON lexer implementation based on a finite state machine.
5 | *
6 | * The authors disclaim copyright to this source code. For more details, see
7 | * the COPYING file included with this distribution.
8 | **/
9 | #endregion
10 |
11 |
12 | using System;
13 | using System.Collections.Generic;
14 | using System.IO;
15 | using System.Text;
16 |
17 |
18 | namespace LitJson
19 | {
20 | internal class FsmContext
21 | {
22 | public bool Return;
23 | public int NextState;
24 | public Lexer L;
25 | public int StateStack;
26 | }
27 |
28 |
29 | internal class Lexer
30 | {
31 | #region Fields
32 | private delegate bool StateHandler (FsmContext ctx);
33 |
34 | private static int[] fsm_return_table;
35 | private static StateHandler[] fsm_handler_table;
36 |
37 | private bool allow_comments;
38 | private bool allow_single_quoted_strings;
39 | private bool end_of_input;
40 | private FsmContext fsm_context;
41 | private int input_buffer;
42 | private int input_char;
43 | private TextReader reader;
44 | private int state;
45 | private StringBuilder string_buffer;
46 | private string string_value;
47 | private int token;
48 | private int unichar;
49 | #endregion
50 |
51 |
52 | #region Properties
53 | public bool AllowComments {
54 | get { return allow_comments; }
55 | set { allow_comments = value; }
56 | }
57 |
58 | public bool AllowSingleQuotedStrings {
59 | get { return allow_single_quoted_strings; }
60 | set { allow_single_quoted_strings = value; }
61 | }
62 |
63 | public bool EndOfInput {
64 | get { return end_of_input; }
65 | }
66 |
67 | public int Token {
68 | get { return token; }
69 | }
70 |
71 | public string StringValue {
72 | get { return string_value; }
73 | }
74 | #endregion
75 |
76 |
77 | #region Constructors
78 | static Lexer ()
79 | {
80 | PopulateFsmTables ();
81 | }
82 |
83 | public Lexer (TextReader reader)
84 | {
85 | allow_comments = true;
86 | allow_single_quoted_strings = true;
87 |
88 | input_buffer = 0;
89 | string_buffer = new StringBuilder (128);
90 | state = 1;
91 | end_of_input = false;
92 | this.reader = reader;
93 |
94 | fsm_context = new FsmContext ();
95 | fsm_context.L = this;
96 | }
97 | #endregion
98 |
99 |
100 | #region Static Methods
101 | private static int HexValue (int digit)
102 | {
103 | switch (digit) {
104 | case 'a':
105 | case 'A':
106 | return 10;
107 |
108 | case 'b':
109 | case 'B':
110 | return 11;
111 |
112 | case 'c':
113 | case 'C':
114 | return 12;
115 |
116 | case 'd':
117 | case 'D':
118 | return 13;
119 |
120 | case 'e':
121 | case 'E':
122 | return 14;
123 |
124 | case 'f':
125 | case 'F':
126 | return 15;
127 |
128 | default:
129 | return digit - '0';
130 | }
131 | }
132 |
133 | private static void PopulateFsmTables ()
134 | {
135 | // See section A.1. of the manual for details of the finite
136 | // state machine.
137 | fsm_handler_table = new StateHandler[28] {
138 | State1,
139 | State2,
140 | State3,
141 | State4,
142 | State5,
143 | State6,
144 | State7,
145 | State8,
146 | State9,
147 | State10,
148 | State11,
149 | State12,
150 | State13,
151 | State14,
152 | State15,
153 | State16,
154 | State17,
155 | State18,
156 | State19,
157 | State20,
158 | State21,
159 | State22,
160 | State23,
161 | State24,
162 | State25,
163 | State26,
164 | State27,
165 | State28
166 | };
167 |
168 | fsm_return_table = new int[28] {
169 | (int) ParserToken.Char,
170 | 0,
171 | (int) ParserToken.Number,
172 | (int) ParserToken.Number,
173 | 0,
174 | (int) ParserToken.Number,
175 | 0,
176 | (int) ParserToken.Number,
177 | 0,
178 | 0,
179 | (int) ParserToken.True,
180 | 0,
181 | 0,
182 | 0,
183 | (int) ParserToken.False,
184 | 0,
185 | 0,
186 | (int) ParserToken.Null,
187 | (int) ParserToken.CharSeq,
188 | (int) ParserToken.Char,
189 | 0,
190 | 0,
191 | (int) ParserToken.CharSeq,
192 | (int) ParserToken.Char,
193 | 0,
194 | 0,
195 | 0,
196 | 0
197 | };
198 | }
199 |
200 | private static char ProcessEscChar (int esc_char)
201 | {
202 | switch (esc_char) {
203 | case '"':
204 | case '\'':
205 | case '\\':
206 | case '/':
207 | return Convert.ToChar (esc_char);
208 |
209 | case 'n':
210 | return '\n';
211 |
212 | case 't':
213 | return '\t';
214 |
215 | case 'r':
216 | return '\r';
217 |
218 | case 'b':
219 | return '\b';
220 |
221 | case 'f':
222 | return '\f';
223 |
224 | default:
225 | // Unreachable
226 | return '?';
227 | }
228 | }
229 |
230 | private static bool State1 (FsmContext ctx)
231 | {
232 | while (ctx.L.GetChar ()) {
233 | if (ctx.L.input_char == ' ' ||
234 | ctx.L.input_char >= '\t' && ctx.L.input_char <= '\r')
235 | continue;
236 |
237 | if (ctx.L.input_char >= '1' && ctx.L.input_char <= '9') {
238 | ctx.L.string_buffer.Append ((char) ctx.L.input_char);
239 | ctx.NextState = 3;
240 | return true;
241 | }
242 |
243 | switch (ctx.L.input_char) {
244 | case '"':
245 | ctx.NextState = 19;
246 | ctx.Return = true;
247 | return true;
248 |
249 | case ',':
250 | case ':':
251 | case '[':
252 | case ']':
253 | case '{':
254 | case '}':
255 | ctx.NextState = 1;
256 | ctx.Return = true;
257 | return true;
258 |
259 | case '-':
260 | ctx.L.string_buffer.Append ((char) ctx.L.input_char);
261 | ctx.NextState = 2;
262 | return true;
263 |
264 | case '0':
265 | ctx.L.string_buffer.Append ((char) ctx.L.input_char);
266 | ctx.NextState = 4;
267 | return true;
268 |
269 | case 'f':
270 | ctx.NextState = 12;
271 | return true;
272 |
273 | case 'n':
274 | ctx.NextState = 16;
275 | return true;
276 |
277 | case 't':
278 | ctx.NextState = 9;
279 | return true;
280 |
281 | case '\'':
282 | if (! ctx.L.allow_single_quoted_strings)
283 | return false;
284 |
285 | ctx.L.input_char = '"';
286 | ctx.NextState = 23;
287 | ctx.Return = true;
288 | return true;
289 |
290 | case '/':
291 | if (! ctx.L.allow_comments)
292 | return false;
293 |
294 | ctx.NextState = 25;
295 | return true;
296 |
297 | default:
298 | return false;
299 | }
300 | }
301 |
302 | return true;
303 | }
304 |
305 | private static bool State2 (FsmContext ctx)
306 | {
307 | ctx.L.GetChar ();
308 |
309 | if (ctx.L.input_char >= '1' && ctx.L.input_char<= '9') {
310 | ctx.L.string_buffer.Append ((char) ctx.L.input_char);
311 | ctx.NextState = 3;
312 | return true;
313 | }
314 |
315 | switch (ctx.L.input_char) {
316 | case '0':
317 | ctx.L.string_buffer.Append ((char) ctx.L.input_char);
318 | ctx.NextState = 4;
319 | return true;
320 |
321 | default:
322 | return false;
323 | }
324 | }
325 |
326 | private static bool State3 (FsmContext ctx)
327 | {
328 | while (ctx.L.GetChar ()) {
329 | if (ctx.L.input_char >= '0' && ctx.L.input_char <= '9') {
330 | ctx.L.string_buffer.Append ((char) ctx.L.input_char);
331 | continue;
332 | }
333 |
334 | if (ctx.L.input_char == ' ' ||
335 | ctx.L.input_char >= '\t' && ctx.L.input_char <= '\r') {
336 | ctx.Return = true;
337 | ctx.NextState = 1;
338 | return true;
339 | }
340 |
341 | switch (ctx.L.input_char) {
342 | case ',':
343 | case ']':
344 | case '}':
345 | ctx.L.UngetChar ();
346 | ctx.Return = true;
347 | ctx.NextState = 1;
348 | return true;
349 |
350 | case '.':
351 | ctx.L.string_buffer.Append ((char) ctx.L.input_char);
352 | ctx.NextState = 5;
353 | return true;
354 |
355 | case 'e':
356 | case 'E':
357 | ctx.L.string_buffer.Append ((char) ctx.L.input_char);
358 | ctx.NextState = 7;
359 | return true;
360 |
361 | default:
362 | return false;
363 | }
364 | }
365 | return true;
366 | }
367 |
368 | private static bool State4 (FsmContext ctx)
369 | {
370 | ctx.L.GetChar ();
371 |
372 | if (ctx.L.input_char == ' ' ||
373 | ctx.L.input_char >= '\t' && ctx.L.input_char <= '\r') {
374 | ctx.Return = true;
375 | ctx.NextState = 1;
376 | return true;
377 | }
378 |
379 | switch (ctx.L.input_char) {
380 | case ',':
381 | case ']':
382 | case '}':
383 | ctx.L.UngetChar ();
384 | ctx.Return = true;
385 | ctx.NextState = 1;
386 | return true;
387 |
388 | case '.':
389 | ctx.L.string_buffer.Append ((char) ctx.L.input_char);
390 | ctx.NextState = 5;
391 | return true;
392 |
393 | case 'e':
394 | case 'E':
395 | ctx.L.string_buffer.Append ((char) ctx.L.input_char);
396 | ctx.NextState = 7;
397 | return true;
398 |
399 | default:
400 | return false;
401 | }
402 | }
403 |
404 | private static bool State5 (FsmContext ctx)
405 | {
406 | ctx.L.GetChar ();
407 |
408 | if (ctx.L.input_char >= '0' && ctx.L.input_char <= '9') {
409 | ctx.L.string_buffer.Append ((char) ctx.L.input_char);
410 | ctx.NextState = 6;
411 | return true;
412 | }
413 |
414 | return false;
415 | }
416 |
417 | private static bool State6 (FsmContext ctx)
418 | {
419 | while (ctx.L.GetChar ()) {
420 | if (ctx.L.input_char >= '0' && ctx.L.input_char <= '9') {
421 | ctx.L.string_buffer.Append ((char) ctx.L.input_char);
422 | continue;
423 | }
424 |
425 | if (ctx.L.input_char == ' ' ||
426 | ctx.L.input_char >= '\t' && ctx.L.input_char <= '\r') {
427 | ctx.Return = true;
428 | ctx.NextState = 1;
429 | return true;
430 | }
431 |
432 | switch (ctx.L.input_char) {
433 | case ',':
434 | case ']':
435 | case '}':
436 | ctx.L.UngetChar ();
437 | ctx.Return = true;
438 | ctx.NextState = 1;
439 | return true;
440 |
441 | case 'e':
442 | case 'E':
443 | ctx.L.string_buffer.Append ((char) ctx.L.input_char);
444 | ctx.NextState = 7;
445 | return true;
446 |
447 | default:
448 | return false;
449 | }
450 | }
451 |
452 | return true;
453 | }
454 |
455 | private static bool State7 (FsmContext ctx)
456 | {
457 | ctx.L.GetChar ();
458 |
459 | if (ctx.L.input_char >= '0' && ctx.L.input_char<= '9') {
460 | ctx.L.string_buffer.Append ((char) ctx.L.input_char);
461 | ctx.NextState = 8;
462 | return true;
463 | }
464 |
465 | switch (ctx.L.input_char) {
466 | case '+':
467 | case '-':
468 | ctx.L.string_buffer.Append ((char) ctx.L.input_char);
469 | ctx.NextState = 8;
470 | return true;
471 |
472 | default:
473 | return false;
474 | }
475 | }
476 |
477 | private static bool State8 (FsmContext ctx)
478 | {
479 | while (ctx.L.GetChar ()) {
480 | if (ctx.L.input_char >= '0' && ctx.L.input_char<= '9') {
481 | ctx.L.string_buffer.Append ((char) ctx.L.input_char);
482 | continue;
483 | }
484 |
485 | if (ctx.L.input_char == ' ' ||
486 | ctx.L.input_char >= '\t' && ctx.L.input_char<= '\r') {
487 | ctx.Return = true;
488 | ctx.NextState = 1;
489 | return true;
490 | }
491 |
492 | switch (ctx.L.input_char) {
493 | case ',':
494 | case ']':
495 | case '}':
496 | ctx.L.UngetChar ();
497 | ctx.Return = true;
498 | ctx.NextState = 1;
499 | return true;
500 |
501 | default:
502 | return false;
503 | }
504 | }
505 |
506 | return true;
507 | }
508 |
509 | private static bool State9 (FsmContext ctx)
510 | {
511 | ctx.L.GetChar ();
512 |
513 | switch (ctx.L.input_char) {
514 | case 'r':
515 | ctx.NextState = 10;
516 | return true;
517 |
518 | default:
519 | return false;
520 | }
521 | }
522 |
523 | private static bool State10 (FsmContext ctx)
524 | {
525 | ctx.L.GetChar ();
526 |
527 | switch (ctx.L.input_char) {
528 | case 'u':
529 | ctx.NextState = 11;
530 | return true;
531 |
532 | default:
533 | return false;
534 | }
535 | }
536 |
537 | private static bool State11 (FsmContext ctx)
538 | {
539 | ctx.L.GetChar ();
540 |
541 | switch (ctx.L.input_char) {
542 | case 'e':
543 | ctx.Return = true;
544 | ctx.NextState = 1;
545 | return true;
546 |
547 | default:
548 | return false;
549 | }
550 | }
551 |
552 | private static bool State12 (FsmContext ctx)
553 | {
554 | ctx.L.GetChar ();
555 |
556 | switch (ctx.L.input_char) {
557 | case 'a':
558 | ctx.NextState = 13;
559 | return true;
560 |
561 | default:
562 | return false;
563 | }
564 | }
565 |
566 | private static bool State13 (FsmContext ctx)
567 | {
568 | ctx.L.GetChar ();
569 |
570 | switch (ctx.L.input_char) {
571 | case 'l':
572 | ctx.NextState = 14;
573 | return true;
574 |
575 | default:
576 | return false;
577 | }
578 | }
579 |
580 | private static bool State14 (FsmContext ctx)
581 | {
582 | ctx.L.GetChar ();
583 |
584 | switch (ctx.L.input_char) {
585 | case 's':
586 | ctx.NextState = 15;
587 | return true;
588 |
589 | default:
590 | return false;
591 | }
592 | }
593 |
594 | private static bool State15 (FsmContext ctx)
595 | {
596 | ctx.L.GetChar ();
597 |
598 | switch (ctx.L.input_char) {
599 | case 'e':
600 | ctx.Return = true;
601 | ctx.NextState = 1;
602 | return true;
603 |
604 | default:
605 | return false;
606 | }
607 | }
608 |
609 | private static bool State16 (FsmContext ctx)
610 | {
611 | ctx.L.GetChar ();
612 |
613 | switch (ctx.L.input_char) {
614 | case 'u':
615 | ctx.NextState = 17;
616 | return true;
617 |
618 | default:
619 | return false;
620 | }
621 | }
622 |
623 | private static bool State17 (FsmContext ctx)
624 | {
625 | ctx.L.GetChar ();
626 |
627 | switch (ctx.L.input_char) {
628 | case 'l':
629 | ctx.NextState = 18;
630 | return true;
631 |
632 | default:
633 | return false;
634 | }
635 | }
636 |
637 | private static bool State18 (FsmContext ctx)
638 | {
639 | ctx.L.GetChar ();
640 |
641 | switch (ctx.L.input_char) {
642 | case 'l':
643 | ctx.Return = true;
644 | ctx.NextState = 1;
645 | return true;
646 |
647 | default:
648 | return false;
649 | }
650 | }
651 |
652 | private static bool State19 (FsmContext ctx)
653 | {
654 | while (ctx.L.GetChar ()) {
655 | switch (ctx.L.input_char) {
656 | case '"':
657 | ctx.L.UngetChar ();
658 | ctx.Return = true;
659 | ctx.NextState = 20;
660 | return true;
661 |
662 | case '\\':
663 | ctx.StateStack = 19;
664 | ctx.NextState = 21;
665 | return true;
666 |
667 | default:
668 | ctx.L.string_buffer.Append ((char) ctx.L.input_char);
669 | continue;
670 | }
671 | }
672 |
673 | return true;
674 | }
675 |
676 | private static bool State20 (FsmContext ctx)
677 | {
678 | ctx.L.GetChar ();
679 |
680 | switch (ctx.L.input_char) {
681 | case '"':
682 | ctx.Return = true;
683 | ctx.NextState = 1;
684 | return true;
685 |
686 | default:
687 | return false;
688 | }
689 | }
690 |
691 | private static bool State21 (FsmContext ctx)
692 | {
693 | ctx.L.GetChar ();
694 |
695 | switch (ctx.L.input_char) {
696 | case 'u':
697 | ctx.NextState = 22;
698 | return true;
699 |
700 | case '"':
701 | case '\'':
702 | case '/':
703 | case '\\':
704 | case 'b':
705 | case 'f':
706 | case 'n':
707 | case 'r':
708 | case 't':
709 | ctx.L.string_buffer.Append (
710 | ProcessEscChar (ctx.L.input_char));
711 | ctx.NextState = ctx.StateStack;
712 | return true;
713 |
714 | default:
715 | return false;
716 | }
717 | }
718 |
719 | private static bool State22 (FsmContext ctx)
720 | {
721 | int counter = 0;
722 | int mult = 4096;
723 |
724 | ctx.L.unichar = 0;
725 |
726 | while (ctx.L.GetChar ()) {
727 |
728 | if (ctx.L.input_char >= '0' && ctx.L.input_char <= '9' ||
729 | ctx.L.input_char >= 'A' && ctx.L.input_char <= 'F' ||
730 | ctx.L.input_char >= 'a' && ctx.L.input_char <= 'f') {
731 |
732 | ctx.L.unichar += HexValue (ctx.L.input_char) * mult;
733 |
734 | counter++;
735 | mult /= 16;
736 |
737 | if (counter == 4) {
738 | ctx.L.string_buffer.Append (
739 | Convert.ToChar (ctx.L.unichar));
740 | ctx.NextState = ctx.StateStack;
741 | return true;
742 | }
743 |
744 | continue;
745 | }
746 |
747 | return false;
748 | }
749 |
750 | return true;
751 | }
752 |
753 | private static bool State23 (FsmContext ctx)
754 | {
755 | while (ctx.L.GetChar ()) {
756 | switch (ctx.L.input_char) {
757 | case '\'':
758 | ctx.L.UngetChar ();
759 | ctx.Return = true;
760 | ctx.NextState = 24;
761 | return true;
762 |
763 | case '\\':
764 | ctx.StateStack = 23;
765 | ctx.NextState = 21;
766 | return true;
767 |
768 | default:
769 | ctx.L.string_buffer.Append ((char) ctx.L.input_char);
770 | continue;
771 | }
772 | }
773 |
774 | return true;
775 | }
776 |
777 | private static bool State24 (FsmContext ctx)
778 | {
779 | ctx.L.GetChar ();
780 |
781 | switch (ctx.L.input_char) {
782 | case '\'':
783 | ctx.L.input_char = '"';
784 | ctx.Return = true;
785 | ctx.NextState = 1;
786 | return true;
787 |
788 | default:
789 | return false;
790 | }
791 | }
792 |
793 | private static bool State25 (FsmContext ctx)
794 | {
795 | ctx.L.GetChar ();
796 |
797 | switch (ctx.L.input_char) {
798 | case '*':
799 | ctx.NextState = 27;
800 | return true;
801 |
802 | case '/':
803 | ctx.NextState = 26;
804 | return true;
805 |
806 | default:
807 | return false;
808 | }
809 | }
810 |
811 | private static bool State26 (FsmContext ctx)
812 | {
813 | while (ctx.L.GetChar ()) {
814 | if (ctx.L.input_char == '\n') {
815 | ctx.NextState = 1;
816 | return true;
817 | }
818 | }
819 |
820 | return true;
821 | }
822 |
823 | private static bool State27 (FsmContext ctx)
824 | {
825 | while (ctx.L.GetChar ()) {
826 | if (ctx.L.input_char == '*') {
827 | ctx.NextState = 28;
828 | return true;
829 | }
830 | }
831 |
832 | return true;
833 | }
834 |
835 | private static bool State28 (FsmContext ctx)
836 | {
837 | while (ctx.L.GetChar ()) {
838 | if (ctx.L.input_char == '*')
839 | continue;
840 |
841 | if (ctx.L.input_char == '/') {
842 | ctx.NextState = 1;
843 | return true;
844 | }
845 |
846 | ctx.NextState = 27;
847 | return true;
848 | }
849 |
850 | return true;
851 | }
852 | #endregion
853 |
854 |
855 | private bool GetChar ()
856 | {
857 | if ((input_char = NextChar ()) != -1)
858 | return true;
859 |
860 | end_of_input = true;
861 | return false;
862 | }
863 |
864 | private int NextChar ()
865 | {
866 | if (input_buffer != 0) {
867 | int tmp = input_buffer;
868 | input_buffer = 0;
869 |
870 | return tmp;
871 | }
872 |
873 | return reader.Read ();
874 | }
875 |
876 | public bool NextToken ()
877 | {
878 | StateHandler handler;
879 | fsm_context.Return = false;
880 |
881 | while (true) {
882 | handler = fsm_handler_table[state - 1];
883 |
884 | if (! handler (fsm_context))
885 | throw new JsonException (input_char);
886 |
887 | if (end_of_input)
888 | return false;
889 |
890 | if (fsm_context.Return) {
891 | string_value = string_buffer.ToString ();
892 | string_buffer.Remove (0, string_buffer.Length);
893 | token = fsm_return_table[state - 1];
894 |
895 | if (token == (int) ParserToken.Char)
896 | token = input_char;
897 |
898 | state = fsm_context.NextState;
899 |
900 | return true;
901 | }
902 |
903 | state = fsm_context.NextState;
904 | }
905 | }
906 |
907 | private void UngetChar ()
908 | {
909 | input_buffer = input_char;
910 | }
911 | }
912 | }
913 |
--------------------------------------------------------------------------------
/Scripts/UOJS/UOJS/LitJson/ParserToken.cs:
--------------------------------------------------------------------------------
1 | #region Header
2 | /**
3 | * ParserToken.cs
4 | * Internal representation of the tokens used by the lexer and the parser.
5 | *
6 | * The authors disclaim copyright to this source code. For more details, see
7 | * the COPYING file included with this distribution.
8 | **/
9 | #endregion
10 |
11 |
12 | namespace LitJson
13 | {
14 | internal enum ParserToken
15 | {
16 | // Lexer tokens (see section A.1.1. of the manual)
17 | None = System.Char.MaxValue + 1,
18 | Number,
19 | True,
20 | False,
21 | Null,
22 | CharSeq,
23 | // Single char
24 | Char,
25 |
26 | // Parser Rules (see section A.2.1 of the manual)
27 | Text,
28 | Object,
29 | ObjectPrime,
30 | Pair,
31 | PairRest,
32 | Array,
33 | ArrayPrime,
34 | Value,
35 | ValueRest,
36 | String,
37 |
38 | // End of input
39 | End,
40 |
41 | // The empty rule
42 | Epsilon
43 | }
44 | }
45 |
--------------------------------------------------------------------------------
/Scripts/UOJS/UOJS/UOJS.cs:
--------------------------------------------------------------------------------
1 | using System;
2 |
3 | namespace UOJS
4 | {
5 | public class UOJS
6 | {
7 | public static readonly string Version = "0.1";
8 | private static readonly string LogPrefix = "UOJS";
9 |
10 | public static void Log (string format, params object[] args)
11 | {
12 | Console.WriteLine (string.Format ("{0}: ", LogPrefix) + string.Format (format, args));
13 | }
14 | }
15 | }
16 |
--------------------------------------------------------------------------------
/Scripts/UOJS/UOJS/Ultima.dll:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kevinhikaruevans/uojs/4385726862f51102196ec8725d8328ce99397e8a/Scripts/UOJS/UOJS/Ultima.dll
--------------------------------------------------------------------------------
/Scripts/UOJS/UOJS/WebSocketClient.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Net.Sockets;
3 |
4 | namespace UOJS
5 | {
6 | ///
7 | /// Web socket client.
8 | ///
9 | public class WebSocketClient
10 | {
11 | ///
12 | /// The size of the max buffer.
13 | ///
14 | public static readonly int MaxBufferSize = 2048;
15 |
16 | private Socket m_WebSocket;
17 | private Socket m_UOClientSocket;
18 | private byte[] m_Buffer, m_UOBuffer;
19 | private bool m_SentHeaders;
20 | private WebSocketPacket m_CurrentPacket;
21 | private DateTime m_CreationTime;
22 |
23 |
24 | ///
25 | /// Gets the creation time.
26 | ///
27 | /// The creation time.
28 | public DateTime CreationTime {
29 | get { return m_CreationTime; }
30 | }
31 |
32 | ///
33 | /// Gets or sets the UO socket.
34 | ///
35 | /// The UO socket.
36 | public Socket UOSocket {
37 | get { return m_UOClientSocket; }
38 | set { m_UOClientSocket = value; }
39 | }
40 | ///
41 | /// Gets or sets the current packet.
42 | ///
43 | /// The current packet.
44 | public WebSocketPacket CurrentPacket {
45 | get { return m_CurrentPacket; }
46 | set { m_CurrentPacket = value; }
47 | }
48 |
49 | ///
50 | /// Gets or sets a value indicating whether the WebSocket's headers have been sent.
51 | ///
52 | /// true if sent headers; otherwise, false.
53 | public bool SentHeaders {
54 | get { return m_SentHeaders; }
55 | set { m_SentHeaders = value; }
56 | }
57 |
58 | ///
59 | /// Gets the web socket.
60 | ///
61 | /// The web socket.
62 | public Socket WebSocket {
63 | get { return m_WebSocket; }
64 | }
65 |
66 | ///
67 | /// Gets or sets the UO write buffer.
68 | ///
69 | /// The UO write buffer.
70 | public byte[] UOWriteBuffer {
71 | get { return m_UOBuffer == null ? (m_UOBuffer = new byte[MaxBufferSize]) : m_UOBuffer; }
72 | set { m_UOBuffer = value; }
73 | }
74 |
75 | ///
76 | /// Gets or sets the WebSocket write buffer.
77 | ///
78 | /// The write buffer.
79 | public byte[] WriteBuffer {
80 | get { return m_Buffer == null ? (m_Buffer = new byte[MaxBufferSize]) : m_Buffer; }
81 | set { m_Buffer = value; }
82 | }
83 |
84 | ///
85 | /// Initializes a new WebSocketClient based on an underlying TCP socket.
86 | ///
87 | /// The underlying TCP socket.
88 | public WebSocketClient (Socket webSocket)
89 | {
90 | m_WebSocket = webSocket;
91 | m_CreationTime = DateTime.Now;
92 | }
93 |
94 | ///
95 | /// Closes the child sockets.
96 | ///
97 | public void Close ()
98 | {
99 | if (m_WebSocket != null && m_WebSocket.Connected) {
100 | UOJS.Log ("Client [{0}]: Closing", m_WebSocket.RemoteEndPoint);
101 | m_WebSocket.Close ();
102 | } else
103 | UOJS.Log ("Client [disposed]: Closed");
104 | if (m_UOClientSocket != null && m_UOClientSocket.Connected)
105 | m_UOClientSocket.Close ();
106 | }
107 | }
108 | }
109 |
110 |
--------------------------------------------------------------------------------
/Scripts/UOJS/UOJS/WebSocketPacket.cs:
--------------------------------------------------------------------------------
1 | using System;
2 |
3 | namespace UOJS
4 | {
5 | public class WebSocketPacket
6 | {
7 | public byte[] Data;
8 | public byte[] Mask;
9 | public int Read;
10 | }
11 | }
12 |
13 |
--------------------------------------------------------------------------------
/Scripts/UOJS/UOJS/bin/Debug/Ultima.dll:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kevinhikaruevans/uojs/4385726862f51102196ec8725d8328ce99397e8a/Scripts/UOJS/UOJS/bin/Debug/Ultima.dll
--------------------------------------------------------------------------------
/Ultima.dll:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kevinhikaruevans/uojs/4385726862f51102196ec8725d8328ce99397e8a/Ultima.dll
--------------------------------------------------------------------------------
/WebClient/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | UO
5 |
6 |
7 |
17 |
55 |
56 |
57 |
58 |
63 |
64 |
65 |
--------------------------------------------------------------------------------