##// END OF EJS Templates
Rewritten JsonScanner, JsonParser, fixed naming style
cin -
r228:6fa235c5a760 v2
parent child
Show More
@@ -0,0 +1,42
1 using Implab.Automaton;
2 using System;
3 using System.Collections.Generic;
4 using System.Linq;
5 using System.Runtime.CompilerServices;
6 using System.Text;
7 using System.Threading.Tasks;
8
9 namespace Implab.Formats {
10 public class CharMap : IAlphabet<char> {
11 readonly char m_min;
12 readonly char m_max;
13 readonly int[] m_map;
14
15 public CharMap(char min, int[] map) {
16 Safe.ArgumentNotNull(map, nameof(map));
17 Count = map.Max()+1;
18 m_min = min;
19 m_map = map;
20 m_max = (char)(min + map.Length);
21 }
22
23 public int Count {
24 get; private set;
25 }
26
27 public bool Contains(char symbol) {
28 return symbol >= m_min && symbol <= m_max && m_map[symbol-m_min] != AutomatonConst.UNCLASSIFIED_INPUT;
29 }
30
31 public IEnumerable<char> GetSymbols(int cls) {
32 for (var i = 0; i < m_map.Length; i++)
33 if (m_map[i] == cls)
34 yield return (char)(i + m_min);
35 }
36
37 [MethodImpl(MethodImplOptions.AggressiveInlining)]
38 public int Translate(char symbol) {
39 return symbol >= m_min && symbol <= m_max ? m_map[symbol-m_min] : AutomatonConst.UNCLASSIFIED_INPUT;
40 }
41 }
42 }
@@ -0,0 +1,84
1 using Implab.Automaton;
2 using System;
3 using System.Collections.Generic;
4 using System.Linq;
5 using System.Text;
6 using System.Threading.Tasks;
7
8 namespace Implab.Formats {
9 public class InputScanner<TTag> {
10 readonly TTag[] m_tags;
11 readonly int m_initialState;
12 readonly int[,] m_dfa;
13 readonly CharMap m_alphabet;
14 readonly bool[] m_final;
15
16 int m_position;
17 int m_state;
18
19 public InputScanner(int[,] dfaTable, bool[] finalStates, TTag[] tags, int initialState, CharMap alphabet) {
20 Safe.ArgumentNotNull(dfaTable, nameof(dfaTable));
21 Safe.ArgumentNotNull(finalStates, nameof(finalStates));
22 Safe.ArgumentNotNull(tags, nameof(tags));
23 Safe.ArgumentNotNull(alphabet, nameof(alphabet));
24
25 m_dfa = dfaTable;
26 m_final = finalStates;
27 m_tags = tags;
28 m_initialState = initialState;
29 m_alphabet = alphabet;
30 }
31
32 public TTag Tag {
33 get {
34 return m_tags[m_state];
35 }
36 }
37
38 public int Position {
39 get {
40 return m_position;
41 }
42 }
43
44 public bool IsFinal {
45 get {
46 return m_final[m_state];
47 }
48 }
49
50 public void Reset() {
51 m_state = m_initialState;
52 }
53
54 public InputScanner<TTag> Clone() {
55 var clone = new InputScanner<TTag>(m_dfa, m_final, m_tags, m_initialState, m_alphabet);
56 clone.m_state = m_state;
57 clone.m_position = m_position;
58 return clone;
59 }
60
61 public bool Scan(char[] data, int offset, int length) {
62 if (length <= 0) {
63 m_position = offset;
64 return false; // EOF
65 }
66
67 var max = offset + length;
68 var next = m_state;
69
70 while(offset < max) {
71 next = m_dfa[next, m_alphabet.Translate(data[offset])];
72 if (next == AutomatonConst.UNREACHABLE_STATE) {
73 // scanner stops on the next position after last recognized symbol
74 m_position = offset;
75 return false;
76 }
77 m_state = next;
78 offset++;
79 }
80 m_position = offset;
81 return true;
82 }
83 }
84 }
@@ -0,0 +1,76
1 using System;
2 using System.Collections.Generic;
3 using System.Linq;
4 using System.Text;
5 using System.Threading.Tasks;
6
7 namespace Implab.Formats.Json {
8 public class JsonStringScanner : JsonScanner {
9 const int _defaultBuffer = 64;
10
11 readonly string m_data;
12 int m_offset;
13
14 JsonStringScanner(string data, char[] buffer, int pos, int length, int offset) : base(buffer, pos, length) {
15 m_data = data;
16 m_offset = offset;
17 }
18
19 protected override int Read(char[] buffer, int offset, int size) {
20 if (m_data == null)
21 return 0;
22 if (m_offset >= m_data.Length)
23 return 0;
24
25 var count = Math.Min(size, m_data.Length - m_offset);
26
27 m_data.CopyTo(m_offset, buffer, offset, count);
28 m_offset += count;
29
30 return count;
31 }
32
33 public static JsonStringScanner Create(string data) {
34 Safe.ArgumentNotNull(data, nameof(data));
35
36 if (data.Length <= _defaultBuffer)
37 return new JsonStringScanner(null, data.ToCharArray(), 0, data.Length, data.Length);
38
39 var buffer = new char[_defaultBuffer];
40 data.CopyTo(0, buffer, 0, _defaultBuffer);
41 return new JsonStringScanner(data, buffer, 0, _defaultBuffer, _defaultBuffer);
42 }
43
44 public static JsonStringScanner Create(string data, int offset, int length) {
45 Safe.ArgumentNotNull(data, nameof(data));
46 Safe.ArgumentGreaterThan(offset, 0, nameof(offset));
47 Safe.ArgumentGreaterThan(length, 0, nameof(length));
48
49 if (offset + length > data.Length)
50 throw new ArgumentOutOfRangeException("Specified offset and length are out of the string bounds");
51
52 if (length <= _defaultBuffer) {
53 var buffer = new char[length];
54 data.CopyTo(offset, buffer, 0, length);
55
56 return new JsonStringScanner(null, buffer, 0, length, length);
57 } else {
58 var buffer = new char[_defaultBuffer];
59 data.CopyTo(offset, buffer, 0, _defaultBuffer);
60 return new JsonStringScanner(data, buffer, 0, _defaultBuffer, offset + _defaultBuffer);
61 }
62 }
63
64 public static JsonStringScanner Create(char[] data, int offset, int length) {
65 Safe.ArgumentNotNull(data, nameof(data));
66 Safe.ArgumentGreaterThan(offset, 0, nameof(offset));
67 Safe.ArgumentGreaterThan(length, 0, nameof(length));
68
69 if (offset + length > data.Length)
70 throw new ArgumentOutOfRangeException("Specified offset and length are out of the array bounds");
71
72 return new JsonStringScanner(null, data, offset, offset + length, offset + length);
73
74 }
75 }
76 }
@@ -0,0 +1,49
1 using System;
2 using System.Collections.Generic;
3 using System.IO;
4 using System.Linq;
5 using System.Text;
6 using System.Threading.Tasks;
7
8 namespace Implab.Formats.Json {
9 public class JsonTextScanner : JsonScanner {
10 const int _bufferSize = 4096;
11 readonly TextReader m_reader;
12
13 JsonTextScanner(TextReader reader, char[] buffer) : base(buffer, 0, 0) {
14 m_reader = reader;
15 }
16
17 protected override int Read(char[] buffer, int offset, int size) {
18 return m_reader.Read(buffer, offset, size);
19 }
20
21 public static JsonTextScanner Create(string file, Encoding encoding) {
22 return new JsonTextScanner(new StreamReader(file, encoding), new char[_bufferSize]);
23 }
24
25 public static JsonTextScanner Create(string file) {
26 return new JsonTextScanner(new StreamReader(file), new char[_bufferSize]);
27 }
28
29 public static JsonTextScanner Create(Stream stream, Encoding encoding) {
30 return new JsonTextScanner(new StreamReader(stream, encoding), new char[_bufferSize]);
31 }
32
33 public static JsonTextScanner Create(Stream stream) {
34 return new JsonTextScanner(new StreamReader(stream), new char[_bufferSize]);
35 }
36
37 public static JsonTextScanner Create(TextReader reader) {
38 Safe.ArgumentNotNull(reader, nameof(reader));
39 return new JsonTextScanner(reader, new char[_bufferSize]);
40 }
41
42 protected override void Dispose(bool disposing) {
43 if (disposing)
44 Safe.Dispose(m_reader);
45
46 base.Dispose(disposing);
47 }
48 }
49 }
@@ -1,145 +1,146
1 using NUnit.Framework;
1 using NUnit.Framework;
2 using System;
2 using System;
3 using Implab.Formats.JSON;
4 using Implab.Automaton;
3 using Implab.Automaton;
5 using Implab.Xml;
4 using Implab.Xml;
6 using System.Xml;
5 using System.Xml;
7 using System.Text;
6 using Implab.Formats;
7 using Implab.Formats.Json;
8
8
9 namespace Implab.Format.Test {
9 namespace Implab.Format.Test {
10 [TestFixture]
10 [TestFixture]
11 public class JsonTests {
11 public class JsonTests {
12
12 [Test]
13 [Test]
13 public void TestScannerValidTokens() {
14 public void TestScannerValidTokens() {
14 using (var scanner = new JSONScanner(@"9123, -123, 0, 0.1, -0.2, -0.1e3, 1.3E-3, ""some \t\n\u0020 text"", literal []{}:")) {
15 using (var scanner = JsonStringScanner.Create(@"9123, -123, 0, 0.1, -0.2, -0.1e3, 1.3E-3, ""some \t\n\u0020 text"", literal []{}:")) {
15
16
16 Tuple<JsonTokenType, object>[] expexted = {
17 Tuple<JsonTokenType, object>[] expexted = {
17 new Tuple<JsonTokenType,object>(JsonTokenType.Number, 9123d),
18 new Tuple<JsonTokenType,object>(JsonTokenType.Number, 9123d),
18 new Tuple<JsonTokenType,object>(JsonTokenType.ValueSeparator, ", "),
19 new Tuple<JsonTokenType,object>(JsonTokenType.ValueSeparator, null),
19 new Tuple<JsonTokenType,object>(JsonTokenType.Number, -123d),
20 new Tuple<JsonTokenType,object>(JsonTokenType.Number, -123d),
20 new Tuple<JsonTokenType,object>(JsonTokenType.ValueSeparator, ", "),
21 new Tuple<JsonTokenType,object>(JsonTokenType.ValueSeparator, null),
21 new Tuple<JsonTokenType,object>(JsonTokenType.Number, 0d),
22 new Tuple<JsonTokenType,object>(JsonTokenType.Number, 0d),
22 new Tuple<JsonTokenType,object>(JsonTokenType.ValueSeparator, ", "),
23 new Tuple<JsonTokenType,object>(JsonTokenType.ValueSeparator, null),
23 new Tuple<JsonTokenType,object>(JsonTokenType.Number, 0.1d),
24 new Tuple<JsonTokenType,object>(JsonTokenType.Number, 0.1d),
24 new Tuple<JsonTokenType,object>(JsonTokenType.ValueSeparator, ", "),
25 new Tuple<JsonTokenType,object>(JsonTokenType.ValueSeparator, null),
25 new Tuple<JsonTokenType,object>(JsonTokenType.Number, -0.2d),
26 new Tuple<JsonTokenType,object>(JsonTokenType.Number, -0.2d),
26 new Tuple<JsonTokenType,object>(JsonTokenType.ValueSeparator, ", "),
27 new Tuple<JsonTokenType,object>(JsonTokenType.ValueSeparator, null),
27 new Tuple<JsonTokenType,object>(JsonTokenType.Number, -0.1e3d),
28 new Tuple<JsonTokenType,object>(JsonTokenType.Number, -0.1e3d),
28 new Tuple<JsonTokenType,object>(JsonTokenType.ValueSeparator, ", "),
29 new Tuple<JsonTokenType,object>(JsonTokenType.ValueSeparator, null),
29 new Tuple<JsonTokenType,object>(JsonTokenType.Number, 1.3E-3d),
30 new Tuple<JsonTokenType,object>(JsonTokenType.Number, 1.3E-3d),
30 new Tuple<JsonTokenType,object>(JsonTokenType.ValueSeparator, ", "),
31 new Tuple<JsonTokenType,object>(JsonTokenType.ValueSeparator, null),
31 new Tuple<JsonTokenType,object>(JsonTokenType.String, "some \t\n text"),
32 new Tuple<JsonTokenType,object>(JsonTokenType.String, "some \t\n text"),
32 new Tuple<JsonTokenType,object>(JsonTokenType.ValueSeparator, ", "),
33 new Tuple<JsonTokenType,object>(JsonTokenType.ValueSeparator, null),
33 new Tuple<JsonTokenType,object>(JsonTokenType.Literal, "literal"),
34 new Tuple<JsonTokenType,object>(JsonTokenType.Literal, "literal"),
34 new Tuple<JsonTokenType,object>(JsonTokenType.BeginArray, " ["),
35 new Tuple<JsonTokenType,object>(JsonTokenType.BeginArray, null),
35 new Tuple<JsonTokenType,object>(JsonTokenType.EndArray, "]"),
36 new Tuple<JsonTokenType,object>(JsonTokenType.EndArray, null),
36 new Tuple<JsonTokenType,object>(JsonTokenType.BeginObject, "{"),
37 new Tuple<JsonTokenType,object>(JsonTokenType.BeginObject, null),
37 new Tuple<JsonTokenType,object>(JsonTokenType.EndObject, "}"),
38 new Tuple<JsonTokenType,object>(JsonTokenType.EndObject, null),
38 new Tuple<JsonTokenType,object>(JsonTokenType.NameSeparator, ":")
39 new Tuple<JsonTokenType,object>(JsonTokenType.NameSeparator, null)
39 };
40 };
40
41
41 object value;
42 object value;
42 JsonTokenType tokenType;
43 JsonTokenType tokenType;
43 for (var i = 0; i < expexted.Length; i++) {
44 for (var i = 0; i < expexted.Length; i++) {
44
45
45 Assert.IsTrue(scanner.ReadToken(out value, out tokenType));
46 Assert.IsTrue(scanner.ReadToken(out value, out tokenType));
46 Assert.AreEqual(expexted[i].Item1, tokenType);
47 Assert.AreEqual(expexted[i].Item1, tokenType);
47 Assert.AreEqual(expexted[i].Item2, value);
48 Assert.AreEqual(expexted[i].Item2, value);
48 }
49 }
49
50
50 Assert.IsFalse(scanner.ReadToken(out value, out tokenType));
51 Assert.IsFalse(scanner.ReadToken(out value, out tokenType));
51 }
52 }
52 }
53 }
53
54
54 [Test]
55 [Test]
55 public void TestScannerBadTokens() {
56 public void TestScannerBadTokens() {
56 var bad = new[] {
57 var bad = new[] {
57 " 1",
58 " 1",
58 " literal",
59 " literal",
59 " \"",
60 " \"",
60 "\"unclosed string",
61 "\"unclosed string",
61 "1.bad",
62 "1.bad",
62 "001", // should be read as three numbers
63 "001", // should be read as three numbers
63 "--10",
64 "--10",
64 "+10",
65 "+10",
65 "1.0.0",
66 "1.0.0",
66 "1e1.0",
67 "1e1.0",
67 "l1teral0",
68 "l1teral0",
68 ".123",
69 ".123",
69 "-.123"
70 "-.123"
70 };
71 };
71
72
72 foreach (var json in bad) {
73 foreach (var json in bad) {
73 using (var scanner = new JSONScanner(json)) {
74 using (var scanner = JsonStringScanner.Create(json)) {
74 try {
75 try {
75 object value;
76 object value;
76 JsonTokenType token;
77 JsonTokenType token;
77 scanner.ReadToken(out value, out token);
78 scanner.ReadToken(out value, out token);
78 if (!Object.Equals(value, json)) {
79 if (!Object.Equals(value, json)) {
79 Console.WriteLine("'{0}' is read as {1}", json, value is String ? String.Format("'{0}'", value) : value);
80 Console.WriteLine("'{0}' is read as {1}", json, value is String ? String.Format("'{0}'", value) : value);
80 continue;
81 continue;
81 }
82 }
82 Assert.Fail("Token '{0}' shouldn't pass", json);
83 Assert.Fail("Token '{0}' shouldn't pass", json);
83 } catch (ParserException e) {
84 } catch (ParserException e) {
84 Console.WriteLine(e.Message);
85 Console.WriteLine(e.Message);
85 }
86 }
86 }
87 }
87 }
88 }
88 }
89 }
89
90
90 [Test]
91 [Test]
91 public void JsonXmlReaderSimpleTest() {
92 public void JsonXmlReaderSimpleTest() {
92 var json = "\"some text\"";
93 var json = "\"some text\"";
93 //Console.WriteLine($"JSON: {json}");
94 //Console.WriteLine($"JSON: {json}");
94 //Console.WriteLine("XML");
95 //Console.WriteLine("XML");
95 /*using (var xmlReader = new JsonXmlReader(new JSONParser(json), new JsonXmlReaderOptions { NamespaceUri = "JsonXmlReaderSimpleTest", RootName = "string", NodesPrefix = "json" })) {
96 /*using (var xmlReader = new JsonXmlReader(new JSONParser(json), new JsonXmlReaderOptions { NamespaceUri = "JsonXmlReaderSimpleTest", RootName = "string", NodesPrefix = "json" })) {
96 Assert.AreEqual(xmlReader.ReadState, System.Xml.ReadState.Initial);
97 Assert.AreEqual(xmlReader.ReadState, System.Xml.ReadState.Initial);
97
98
98 AssertRead(xmlReader, XmlNodeType.XmlDeclaration);
99 AssertRead(xmlReader, XmlNodeType.XmlDeclaration);
99 AssertRead(xmlReader, XmlNodeType.Element);
100 AssertRead(xmlReader, XmlNodeType.Element);
100 AssertRead(xmlReader, XmlNodeType.Text);
101 AssertRead(xmlReader, XmlNodeType.Text);
101 AssertRead(xmlReader, XmlNodeType.EndElement);
102 AssertRead(xmlReader, XmlNodeType.EndElement);
102 Assert.IsFalse(xmlReader.Read());
103 Assert.IsFalse(xmlReader.Read());
103 }*/
104 }*/
104
105
105 //DumpJsonParse("\"text value\"");
106 //DumpJsonParse("\"text value\"");
106 //DumpJsonParse("null");
107 //DumpJsonParse("null");
107 //DumpJsonParse("true");
108 //DumpJsonParse("true");
108 //DumpJsonParse("{}");
109 //DumpJsonParse("{}");
109 //DumpJsonParse("[]");
110 //DumpJsonParse("[]");
110 DumpJsonParse("{\"one\":1, \"two\":2}");
111 DumpJsonParse("{\"one\":1, \"two\":2}");
111 DumpJsonParse("[1,2,3]");
112 DumpJsonParse("[1,2,3]");
112 DumpJsonParse("[{\"info\": [7,8,9]}]");
113 DumpJsonParse("[{\"info\": [7,8,9]}]");
113 DumpJsonFlatParse("[1,2,[3,4],{\"info\": [5,6]},{\"num\": [7,8,null]}, null,[null]]");
114 DumpJsonFlatParse("[1,2,[3,4],{\"info\": [5,6]},{\"num\": [7,8,null]}, null,[null]]");
114 }
115 }
115
116
116 void AssertRead(XmlReader reader, XmlNodeType expected) {
117 void AssertRead(XmlReader reader, XmlNodeType expected) {
117 Assert.IsTrue(reader.Read());
118 Assert.IsTrue(reader.Read());
118 Console.WriteLine($"{new string(' ', reader.Depth*2)}{reader}");
119 Console.WriteLine($"{new string(' ', reader.Depth*2)}{reader}");
119 Assert.AreEqual(expected, reader.NodeType);
120 Assert.AreEqual(expected, reader.NodeType);
120 }
121 }
121
122
122 void DumpJsonParse(string json) {
123 void DumpJsonParse(string json) {
123 Console.WriteLine($"JSON: {json}");
124 Console.WriteLine($"JSON: {json}");
124 Console.WriteLine("XML");
125 Console.WriteLine("XML");
125 using (var xmlReader = new JsonXmlReader(new JSONParser(json), new JsonXmlReaderOptions { NamespaceUri = "JsonXmlReaderSimpleTest", NodesPrefix = "json" })) {
126 using (var xmlReader = new JsonXmlReader(new JsonParser(json), new JsonXmlReaderOptions { NamespaceUri = "JsonXmlReaderSimpleTest", NodesPrefix = "json" })) {
126 while (xmlReader.Read())
127 while (xmlReader.Read())
127 Console.WriteLine($"{new string(' ', xmlReader.Depth * 2)}{xmlReader}");
128 Console.WriteLine($"{new string(' ', xmlReader.Depth * 2)}{xmlReader}");
128 }
129 }
129 }
130 }
130
131
131 void DumpJsonFlatParse(string json) {
132 void DumpJsonFlatParse(string json) {
132 Console.WriteLine($"JSON: {json}");
133 Console.WriteLine($"JSON: {json}");
133 Console.WriteLine("XML");
134 Console.WriteLine("XML");
134 using (var xmlWriter = XmlWriter.Create(Console.Out, new XmlWriterSettings {
135 using (var xmlWriter = XmlWriter.Create(Console.Out, new XmlWriterSettings {
135 Indent = true,
136 Indent = true,
136 CloseOutput = false,
137 CloseOutput = false,
137 ConformanceLevel = ConformanceLevel.Document
138 ConformanceLevel = ConformanceLevel.Document
138 }))
139 }))
139 using (var xmlReader = new JsonXmlReader(new JSONParser(json), new JsonXmlReaderOptions { NamespaceUri = "JsonXmlReaderSimpleTest", NodesPrefix = "", FlattenArrays = true })) {
140 using (var xmlReader = new JsonXmlReader(new JsonParser(json), new JsonXmlReaderOptions { NamespaceUri = "JsonXmlReaderSimpleTest", NodesPrefix = "", FlattenArrays = true })) {
140 xmlWriter.WriteNode(xmlReader, false);
141 xmlWriter.WriteNode(xmlReader, false);
141 }
142 }
142 }
143 }
143 }
144 }
144 }
145 }
145
146
@@ -1,16 +1,36
1 using System.Collections.Generic;
1 using System.Collections.Generic;
2 using System.Linq;
2 using System.Linq;
3 using Implab.Automaton;
3 using Implab.Automaton;
4 using System;
4
5
5 namespace Implab.Formats {
6 namespace Implab.Formats {
6 public class CharAlphabet: IndexedAlphabetBase<char> {
7 public class CharAlphabet: IndexedAlphabetBase<char> {
7
8
8 public override int GetSymbolIndex(char symbol) {
9 public override int GetSymbolIndex(char symbol) {
9 return symbol;
10 return symbol;
10 }
11 }
11
12
12 public IEnumerable<char> InputSymbols {
13 public IEnumerable<char> InputSymbols {
13 get { return Enumerable.Range(char.MinValue, char.MaxValue).Cast<char>(); }
14 get { return Enumerable.Range(char.MinValue, char.MaxValue).Cast<char>(); }
14 }
15 }
16
17 public CharMap CreateCharMap() {
18 var map = new Dictionary<int, int>();
19
20 int max = 0, min = char.MaxValue;
21 foreach (var p in Mappings) {
22 var index = GetSymbolIndex(p.Key);
23 max = Math.Max(max, index);
24 min = Math.Min(min, index);
25 map[index] = p.Value;
26 }
27
28 var result = new int[max - min + 1];
29
30 for (int i = 0; i < result.Length; i++)
31 map.TryGetValue(min + i, out result[i]);
32
33 return new CharMap((char)min, result);
34 }
15 }
35 }
16 }
36 }
@@ -1,99 +1,73
1 using Implab;
1 using Implab;
2 using System;
2 using System;
3 using System.Collections.Generic;
3 using System.Collections.Generic;
4 using System.Linq;
4 using System.Linq;
5 using Implab.Automaton;
5 using Implab.Automaton;
6 using Implab.Automaton.RegularExpressions;
6 using Implab.Automaton.RegularExpressions;
7
7
8 namespace Implab.Formats {
8 namespace Implab.Formats {
9 /// <summary>
9 /// <summary>
10 /// Базовый абстрактный класс. Грамматика, позволяет формулировать выражения над алфавитом типа <c>char</c>.
10 /// Базовый абстрактный класс. Грамматика, позволяет формулировать выражения над алфавитом типа <c>char</c>.
11 /// </summary>
11 /// </summary>
12 public abstract class Grammar<TSymbol> {
12 public abstract class Grammar<TSymbol> {
13
13
14 protected abstract IAlphabetBuilder<TSymbol> AlphabetBuilder {
14 protected abstract IAlphabetBuilder<TSymbol> AlphabetBuilder {
15 get;
15 get;
16 }
16 }
17
17
18 protected SymbolToken UnclassifiedToken() {
18 protected SymbolToken UnclassifiedToken() {
19 return new SymbolToken(AutomatonConst.UNCLASSIFIED_INPUT);
19 return new SymbolToken(AutomatonConst.UNCLASSIFIED_INPUT);
20 }
20 }
21
21
22 protected void DefineAlphabet(IEnumerable<TSymbol> alphabet) {
22 protected void DefineAlphabet(IEnumerable<TSymbol> alphabet) {
23 Safe.ArgumentNotNull(alphabet, "alphabet");
23 Safe.ArgumentNotNull(alphabet, "alphabet");
24
24
25 foreach (var ch in alphabet)
25 foreach (var ch in alphabet)
26 AlphabetBuilder.DefineSymbol(ch);
26 AlphabetBuilder.DefineSymbol(ch);
27 }
27 }
28
28
29 protected Token SymbolToken(TSymbol symbol) {
29 protected Token SymbolToken(TSymbol symbol) {
30 return Token.New(TranslateOrAdd(symbol));
30 return Token.New(TranslateOrAdd(symbol));
31 }
31 }
32
32
33 protected Token SymbolToken(IEnumerable<TSymbol> symbols) {
33 protected Token SymbolToken(IEnumerable<TSymbol> symbols) {
34 Safe.ArgumentNotNull(symbols, "symbols");
34 Safe.ArgumentNotNull(symbols, "symbols");
35
35
36 return Token.New(TranslateOrAdd(symbols).ToArray());
36 return Token.New(TranslateOrAdd(symbols).ToArray());
37 }
37 }
38
38
39 protected Token SymbolSetToken(params TSymbol[] set) {
39 protected Token SymbolSetToken(params TSymbol[] set) {
40 return SymbolToken(set);
40 return SymbolToken(set);
41 }
41 }
42
42
43 int TranslateOrAdd(TSymbol ch) {
43 int TranslateOrAdd(TSymbol ch) {
44 var t = AlphabetBuilder.Translate(ch);
44 var t = AlphabetBuilder.Translate(ch);
45 if (t == AutomatonConst.UNCLASSIFIED_INPUT)
45 if (t == AutomatonConst.UNCLASSIFIED_INPUT)
46 t = AlphabetBuilder.DefineSymbol(ch);
46 t = AlphabetBuilder.DefineSymbol(ch);
47 return t;
47 return t;
48 }
48 }
49
49
50 IEnumerable<int> TranslateOrAdd(IEnumerable<TSymbol> symbols) {
50 IEnumerable<int> TranslateOrAdd(IEnumerable<TSymbol> symbols) {
51 return symbols.Distinct().Select(TranslateOrAdd);
51 return symbols.Distinct().Select(TranslateOrAdd);
52 }
52 }
53
53
54 int TranslateOrDie(TSymbol ch) {
54 int TranslateOrDie(TSymbol ch) {
55 var t = AlphabetBuilder.Translate(ch);
55 var t = AlphabetBuilder.Translate(ch);
56 if (t == AutomatonConst.UNCLASSIFIED_INPUT)
56 if (t == AutomatonConst.UNCLASSIFIED_INPUT)
57 throw new ApplicationException(String.Format("Symbol '{0}' is UNCLASSIFIED", ch));
57 throw new ApplicationException(String.Format("Symbol '{0}' is UNCLASSIFIED", ch));
58 return t;
58 return t;
59 }
59 }
60
60
61 IEnumerable<int> TranslateOrDie(IEnumerable<TSymbol> symbols) {
61 IEnumerable<int> TranslateOrDie(IEnumerable<TSymbol> symbols) {
62 return symbols.Distinct().Select(TranslateOrDie);
62 return symbols.Distinct().Select(TranslateOrDie);
63 }
63 }
64
64
65 protected Token SymbolTokenExcept(IEnumerable<TSymbol> symbols) {
65 protected Token SymbolTokenExcept(IEnumerable<TSymbol> symbols) {
66 Safe.ArgumentNotNull(symbols, "symbols");
66 Safe.ArgumentNotNull(symbols, "symbols");
67
67
68 return Token.New( Enumerable.Range(0, AlphabetBuilder.Count).Except(TranslateOrDie(symbols)).ToArray() );
68 return Token.New( Enumerable.Range(0, AlphabetBuilder.Count).Except(TranslateOrDie(symbols)).ToArray() );
69 }
69 }
70
71 protected abstract IndexedAlphabetBase<TSymbol> CreateAlphabet();
72
73 protected ScannerContext<TTag> BuildScannerContext<TTag>(Token regexp) {
74
75 var dfa = new RegularDFA<TSymbol, TTag>(AlphabetBuilder);
76
77 var visitor = new RegularExpressionVisitor<TTag>(dfa);
78 regexp.Accept(visitor);
79 visitor.BuildDFA();
80
81 if (dfa.IsFinalState(dfa.InitialState))
82 throw new ApplicationException("The specified language contains empty token");
83
84 var ab = CreateAlphabet();
85 var optimal = dfa.Optimize(ab);
86
87 return new ScannerContext<TTag>(
88 optimal.CreateTransitionTable(),
89 optimal.CreateFinalStateTable(),
90 optimal.CreateTagTable(),
91 optimal.InitialState,
92 ab.GetTranslationMap()
93 );
94 }
95
96 }
70 }
97
71
98
72
99 }
73 }
@@ -1,11 +1,11
1 namespace Implab.Formats.JSON {
1 namespace Implab.Formats.Json {
2 /// <summary>
2 /// <summary>
3 /// internal
3 /// internal
4 /// </summary>
4 /// </summary>
5 enum JSONElementContext {
5 enum JsonElementContext {
6 None,
6 None,
7 Object,
7 Object,
8 Array,
8 Array,
9 Closed
9 Closed
10 }
10 }
11 }
11 }
@@ -1,28 +1,28
1 namespace Implab.Formats.JSON {
1 namespace Implab.Formats.Json {
2 /// <summary>
2 /// <summary>
3 /// Тип элемента на котором находится парсер
3 /// Тип элемента на котором находится парсер
4 /// </summary>
4 /// </summary>
5 public enum JSONElementType {
5 public enum JsonElementType {
6 None,
6 None,
7 /// <summary>
7 /// <summary>
8 /// Начало объекта
8 /// Начало объекта
9 /// </summary>
9 /// </summary>
10 BeginObject,
10 BeginObject,
11 /// <summary>
11 /// <summary>
12 /// Конец объекта
12 /// Конец объекта
13 /// </summary>
13 /// </summary>
14 EndObject,
14 EndObject,
15 /// <summary>
15 /// <summary>
16 /// Начало массива
16 /// Начало массива
17 /// </summary>
17 /// </summary>
18 BeginArray,
18 BeginArray,
19 /// <summary>
19 /// <summary>
20 /// Конец массива
20 /// Конец массива
21 /// </summary>
21 /// </summary>
22 EndArray,
22 EndArray,
23 /// <summary>
23 /// <summary>
24 /// Простое значение
24 /// Простое значение
25 /// </summary>
25 /// </summary>
26 Value
26 Value
27 }
27 }
28 }
28 }
@@ -1,121 +1,148
1 using System.Linq;
1 using System.Linq;
2 using Implab.Automaton.RegularExpressions;
2 using Implab.Automaton.RegularExpressions;
3 using System;
3 using System;
4 using Implab.Automaton;
4 using Implab.Automaton;
5 using Implab.Components;
5 using Implab.Components;
6
6
7 namespace Implab.Formats.JSON {
7 namespace Implab.Formats.Json {
8 class JSONGrammar : Grammar<char> {
8 public class JsonGrammar : Grammar<char> {
9 public enum TokenType {
9 public enum TokenType {
10 None,
10 None,
11 BeginObject,
11 BeginObject,
12 EndObject,
12 EndObject,
13 BeginArray,
13 BeginArray,
14 EndArray,
14 EndArray,
15 String,
15 String,
16 Number,
16 Number,
17 Literal,
17 Literal,
18 NameSeparator,
18 NameSeparator,
19 ValueSeparator,
19 ValueSeparator,
20 Whitespace,
20 Whitespace,
21
21
22 StringBound,
22 StringBound,
23 EscapedChar,
23 EscapedChar,
24 UnescapedChar,
24 UnescapedChar,
25 EscapedUnicode
25 EscapedUnicode
26 }
26 }
27
27
28 static LazyAndWeak<JSONGrammar> _instance = new LazyAndWeak<JSONGrammar>(() => new JSONGrammar());
28 static LazyAndWeak<JsonGrammar> _instance = new LazyAndWeak<JsonGrammar>(() => new JsonGrammar());
29
29
30 public static JSONGrammar Instance {
30 public static JsonGrammar Instance {
31 get { return _instance.Value; }
31 get { return _instance.Value; }
32 }
32 }
33
33
34 readonly ScannerContext<TokenType> m_jsonExpression;
34 readonly InputScanner<TokenType> m_jsonExpression;
35 readonly ScannerContext<TokenType> m_stringExpression;
35 readonly InputScanner<TokenType> m_stringExpression;
36 readonly CharAlphabet m_defaultAlphabet = new CharAlphabet();
36 readonly CharAlphabet m_defaultAlphabet = new CharAlphabet();
37
37
38 public JSONGrammar() {
38 public CharAlphabet DefaultAlphabet { get { return m_defaultAlphabet; } }
39
40 public JsonGrammar() {
39 DefineAlphabet(Enumerable.Range(0, 0x20).Select(x => (char)x));
41 DefineAlphabet(Enumerable.Range(0, 0x20).Select(x => (char)x));
40 var hexDigit = SymbolRangeToken('a','f').Or(SymbolRangeToken('A','F')).Or(SymbolRangeToken('0','9'));
42 var hexDigit = SymbolRangeToken('a','f').Or(SymbolRangeToken('A','F')).Or(SymbolRangeToken('0','9'));
41 var digit9 = SymbolRangeToken('1', '9');
43 var digit9 = SymbolRangeToken('1', '9');
42 var zero = SymbolToken('0');
44 var zero = SymbolToken('0');
43 var digit = zero.Or(digit9);
45 var digit = zero.Or(digit9);
44 var dot = SymbolToken('.');
46 var dot = SymbolToken('.');
45 var minus = SymbolToken('-');
47 var minus = SymbolToken('-');
46 var sign = SymbolSetToken('-', '+');
48 var sign = SymbolSetToken('-', '+');
47 var expSign = SymbolSetToken('e', 'E');
49 var expSign = SymbolSetToken('e', 'E');
48 var letters = SymbolRangeToken('a', 'z');
50 var letters = SymbolRangeToken('a', 'z');
49 var integer = zero.Or(digit9.Cat(digit.EClosure()));
51 var integer = zero.Or(digit9.Cat(digit.EClosure()));
50 var frac = dot.Cat(digit.Closure());
52 var frac = dot.Cat(digit.Closure());
51 var exp = expSign.Cat(sign.Optional()).Cat(digit.Closure());
53 var exp = expSign.Cat(sign.Optional()).Cat(digit.Closure());
52 var quote = SymbolToken('"');
54 var quote = SymbolToken('"');
53 var backSlash = SymbolToken('\\');
55 var backSlash = SymbolToken('\\');
54 var specialEscapeChars = SymbolSetToken('\\', '"', '/', 'b', 'f', 't', 'n', 'r');
56 var specialEscapeChars = SymbolSetToken('\\', '"', '/', 'b', 'f', 't', 'n', 'r');
55 var unicodeEspace = SymbolToken('u').Cat(hexDigit.Repeat(4));
57 var unicodeEspace = SymbolToken('u').Cat(hexDigit.Repeat(4));
56 var whitespace = SymbolSetToken('\n', '\r', '\t', ' ').EClosure();
58 var whitespace = SymbolSetToken('\n', '\r', '\t', ' ').EClosure();
57 var beginObject = whitespace.Cat(SymbolToken('{')).Cat(whitespace);
59 var beginObject = whitespace.Cat(SymbolToken('{')).Cat(whitespace);
58 var endObject = whitespace.Cat(SymbolToken('}')).Cat(whitespace);
60 var endObject = whitespace.Cat(SymbolToken('}')).Cat(whitespace);
59 var beginArray = whitespace.Cat(SymbolToken('[')).Cat(whitespace);
61 var beginArray = whitespace.Cat(SymbolToken('[')).Cat(whitespace);
60 var endArray = whitespace.Cat(SymbolToken(']')).Cat(whitespace);
62 var endArray = whitespace.Cat(SymbolToken(']')).Cat(whitespace);
61 var nameSep = whitespace.Cat(SymbolToken(':')).Cat(whitespace);
63 var nameSep = whitespace.Cat(SymbolToken(':')).Cat(whitespace);
62 var valueSep = whitespace.Cat(SymbolToken(',')).Cat(whitespace);
64 var valueSep = whitespace.Cat(SymbolToken(',')).Cat(whitespace);
63
65
64 var number = minus.Optional().Cat(integer).Cat(frac.Optional()).Cat(exp.Optional());
66 var number = minus.Optional().Cat(integer).Cat(frac.Optional()).Cat(exp.Optional());
65 var literal = letters.Closure();
67 var literal = letters.Closure();
66 var unescaped = SymbolTokenExcept(Enumerable.Range(0, 0x20).Union(new int[] { '\\', '"' }).Select(x => (char)x));
68 var unescaped = SymbolTokenExcept(Enumerable.Range(0, 0x20).Union(new int[] { '\\', '"' }).Select(x => (char)x));
67
69
68 var jsonExpression =
70 var jsonExpression =
69 number.Tag(TokenType.Number)
71 number.Tag(TokenType.Number)
70 .Or(literal.Tag(TokenType.Literal))
72 .Or(literal.Tag(TokenType.Literal))
71 .Or(quote.Tag(TokenType.StringBound))
73 .Or(quote.Tag(TokenType.StringBound))
72 .Or(beginObject.Tag(TokenType.BeginObject))
74 .Or(beginObject.Tag(TokenType.BeginObject))
73 .Or(endObject.Tag(TokenType.EndObject))
75 .Or(endObject.Tag(TokenType.EndObject))
74 .Or(beginArray.Tag(TokenType.BeginArray))
76 .Or(beginArray.Tag(TokenType.BeginArray))
75 .Or(endArray.Tag(TokenType.EndArray))
77 .Or(endArray.Tag(TokenType.EndArray))
76 .Or(nameSep.Tag(TokenType.NameSeparator))
78 .Or(nameSep.Tag(TokenType.NameSeparator))
77 .Or(valueSep.Tag(TokenType.ValueSeparator))
79 .Or(valueSep.Tag(TokenType.ValueSeparator))
78 .Or(SymbolSetToken('\n', '\r', '\t', ' ').Closure().Tag(TokenType.Whitespace));
80 .Or(SymbolSetToken('\n', '\r', '\t', ' ').Closure().Tag(TokenType.Whitespace));
79
81
80
82
81 var jsonStringExpression =
83 var jsonStringExpression =
82 quote.Tag(TokenType.StringBound)
84 quote.Tag(TokenType.StringBound)
83 .Or(backSlash.Cat(specialEscapeChars).Tag(TokenType.EscapedChar))
85 .Or(backSlash.Cat(specialEscapeChars).Tag(TokenType.EscapedChar))
84 .Or(backSlash.Cat(unicodeEspace).Tag(TokenType.EscapedUnicode))
86 .Or(backSlash.Cat(unicodeEspace).Tag(TokenType.EscapedUnicode))
85 .Or(unescaped.Closure().Tag(TokenType.UnescapedChar));
87 .Or(unescaped.Closure().Tag(TokenType.UnescapedChar));
86
88
87
89
88 m_jsonExpression = BuildScannerContext<TokenType>(jsonExpression);
90 m_jsonExpression = BuildScanner(jsonExpression);
89 m_stringExpression = BuildScannerContext<TokenType>(jsonStringExpression);
91 m_stringExpression = BuildScanner(jsonStringExpression);
92 }
90
93
94 public static InputScanner<TokenType> CreateJsonExpressionScanner() {
95 return Instance.m_jsonExpression.Clone();
96 }
91
97
98 public static InputScanner<TokenType> CreateStringExpressionScanner() {
99 return Instance.m_stringExpression.Clone();
92 }
100 }
93
101
94 protected override IAlphabetBuilder<char> AlphabetBuilder {
102 protected override IAlphabetBuilder<char> AlphabetBuilder {
95 get {
103 get {
96 return m_defaultAlphabet;
104 return m_defaultAlphabet;
97 }
105 }
98 }
106 }
99
107
100 public ScannerContext<TokenType> JsonExpression {
101 get {
102 return m_jsonExpression;
103 }
104 }
105
106 public ScannerContext<TokenType> JsonStringExpression {
107 get {
108 return m_stringExpression;
109 }
110 }
111
112 Token SymbolRangeToken(char start, char stop) {
108 Token SymbolRangeToken(char start, char stop) {
113 return SymbolToken(Enumerable.Range(start, stop - start + 1).Select(x => (char)x));
109 return SymbolToken(Enumerable.Range(start, stop - start + 1).Select(x => (char)x));
114 }
110 }
115
111
116 protected override IndexedAlphabetBase<char> CreateAlphabet() {
112 public InputScanner<TokenType> BuildScanner(Token regexp) {
117 return new CharAlphabet();
113 var dfa = new RegularDFA<char, TokenType>(AlphabetBuilder);
114
115 var visitor = new RegularExpressionVisitor<TokenType>(dfa);
116 regexp.Accept(visitor);
117 visitor.BuildDFA();
118
119 if (dfa.IsFinalState(dfa.InitialState))
120 throw new ApplicationException("The specified language contains empty token");
121
122 var ab = new CharAlphabet();
123 var optimal = dfa.Optimize(ab);
124
125 return new InputScanner<TokenType>(
126 optimal.CreateTransitionTable(),
127 optimal.CreateFinalStateTable(),
128 NormalizeTags(optimal.CreateTagTable()),
129 optimal.InitialState,
130 ab.CreateCharMap()
131 );
132 }
133
134 static TokenType[] NormalizeTags(TokenType[][] tags) {
135 var result = new TokenType[tags.Length];
136 for(var i = 0; i< tags.Length; i++) {
137 if (tags[i] == null || tags[i].Length == 0)
138 result[i] = default(TokenType);
139 else if (tags[i].Length == 1)
140 result[i] = tags[i][0];
141 else
142 throw new Exception($"Ambigous state tags {string.Join(", ", tags[i])}");
143 }
144 return result;
118 }
145 }
119
146
120 }
147 }
121 }
148 }
@@ -1,294 +1,294
1 using System;
1 using System;
2 using System.Diagnostics;
2 using System.Diagnostics;
3 using System.IO;
3 using System.IO;
4 using Implab.Automaton;
4 using Implab.Automaton;
5 using Implab.Automaton.RegularExpressions;
5 using Implab.Automaton.RegularExpressions;
6 using System.Linq;
6 using System.Linq;
7 using Implab.Components;
7 using Implab.Components;
8 using System.Collections.Generic;
8 using System.Collections.Generic;
9
9
10 namespace Implab.Formats.JSON {
10 namespace Implab.Formats.Json {
11 /// <summary>
11 /// <summary>
12 /// Pull парсер JSON данных.
12 /// Pull парсер JSON данных.
13 /// </summary>
13 /// </summary>
14 /// <remarks>
14 /// <remarks>
15 /// Следует отметить отдельную интерпретацию свойства <see cref="Level"/>,
15 /// Следует отметить отдельную интерпретацию свойства <see cref="Level"/>,
16 /// оно означает текущий уровень вложенности объектов, однако закрывающий
16 /// оно означает текущий уровень вложенности объектов, однако закрывающий
17 /// элемент объекта и массива имеет уровень меньше, чем сам объект.
17 /// элемент объекта и массива имеет уровень меньше, чем сам объект.
18 /// <code>
18 /// <code>
19 /// { // Level = 1
19 /// { // Level = 1
20 /// "name" : "Peter", // Level = 1
20 /// "name" : "Peter", // Level = 1
21 /// "address" : { // Level = 2
21 /// "address" : { // Level = 2
22 /// city : "Stern" // Level = 2
22 /// city : "Stern" // Level = 2
23 /// } // Level = 1
23 /// } // Level = 1
24 /// } // Level = 0
24 /// } // Level = 0
25 /// </code>
25 /// </code>
26 /// </remarks>
26 /// </remarks>
27 public class JSONParser : Disposable {
27 public class JsonParser : Disposable {
28
28
29 enum MemberContext {
29 enum MemberContext {
30 MemberName,
30 MemberName,
31 MemberValue
31 MemberValue
32 }
32 }
33
33
34 #region Parser rules
34 #region Parser rules
35 struct ParserContext {
35 struct ParserContext {
36 readonly int[,] m_dfa;
36 readonly int[,] m_dfa;
37 int m_state;
37 int m_state;
38
38
39 readonly JSONElementContext m_elementContext;
39 readonly JsonElementContext m_elementContext;
40
40
41 public ParserContext(int[,] dfa, int state, JSONElementContext context) {
41 public ParserContext(int[,] dfa, int state, JsonElementContext context) {
42 m_dfa = dfa;
42 m_dfa = dfa;
43 m_state = state;
43 m_state = state;
44 m_elementContext = context;
44 m_elementContext = context;
45 }
45 }
46
46
47 public bool Move(JsonTokenType token) {
47 public bool Move(JsonTokenType token) {
48 var next = m_dfa[m_state, (int)token];
48 var next = m_dfa[m_state, (int)token];
49 if (next == AutomatonConst.UNREACHABLE_STATE)
49 if (next == AutomatonConst.UNREACHABLE_STATE)
50 return false;
50 return false;
51 m_state = next;
51 m_state = next;
52 return true;
52 return true;
53 }
53 }
54
54
55 public JSONElementContext ElementContext {
55 public JsonElementContext ElementContext {
56 get { return m_elementContext; }
56 get { return m_elementContext; }
57 }
57 }
58 }
58 }
59
59
60 static readonly ParserContext _jsonContext;
60 static readonly ParserContext _jsonContext;
61 static readonly ParserContext _objectContext;
61 static readonly ParserContext _objectContext;
62 static readonly ParserContext _arrayContext;
62 static readonly ParserContext _arrayContext;
63
63
64 static JSONParser() {
64 static JsonParser() {
65
65
66 var valueExpression = MakeToken(JsonTokenType.BeginArray, JsonTokenType.BeginObject, JsonTokenType.Literal, JsonTokenType.Number, JsonTokenType.String);
66 var valueExpression = MakeToken(JsonTokenType.BeginArray, JsonTokenType.BeginObject, JsonTokenType.Literal, JsonTokenType.Number, JsonTokenType.String);
67 var memberExpression = MakeToken(JsonTokenType.String).Cat(MakeToken(JsonTokenType.NameSeparator)).Cat(valueExpression);
67 var memberExpression = MakeToken(JsonTokenType.String).Cat(MakeToken(JsonTokenType.NameSeparator)).Cat(valueExpression);
68
68
69 var objectExpression = memberExpression
69 var objectExpression = memberExpression
70 .Cat(
70 .Cat(
71 MakeToken(JsonTokenType.ValueSeparator)
71 MakeToken(JsonTokenType.ValueSeparator)
72 .Cat(memberExpression)
72 .Cat(memberExpression)
73 .EClosure()
73 .EClosure()
74 )
74 )
75 .Optional()
75 .Optional()
76 .Cat(MakeToken(JsonTokenType.EndObject))
76 .Cat(MakeToken(JsonTokenType.EndObject))
77 .End();
77 .End();
78
78
79 var arrayExpression = valueExpression
79 var arrayExpression = valueExpression
80 .Cat(
80 .Cat(
81 MakeToken(JsonTokenType.ValueSeparator)
81 MakeToken(JsonTokenType.ValueSeparator)
82 .Cat(valueExpression)
82 .Cat(valueExpression)
83 .EClosure()
83 .EClosure()
84 )
84 )
85 .Optional()
85 .Optional()
86 .Cat(MakeToken(JsonTokenType.EndArray))
86 .Cat(MakeToken(JsonTokenType.EndArray))
87 .End();
87 .End();
88
88
89 var jsonExpression = valueExpression.End();
89 var jsonExpression = valueExpression.End();
90
90
91 _jsonContext = CreateParserContext(jsonExpression, JSONElementContext.None);
91 _jsonContext = CreateParserContext(jsonExpression, JsonElementContext.None);
92 _objectContext = CreateParserContext(objectExpression, JSONElementContext.Object);
92 _objectContext = CreateParserContext(objectExpression, JsonElementContext.Object);
93 _arrayContext = CreateParserContext(arrayExpression, JSONElementContext.Array);
93 _arrayContext = CreateParserContext(arrayExpression, JsonElementContext.Array);
94 }
94 }
95
95
96 static Token MakeToken(params JsonTokenType[] input) {
96 static Token MakeToken(params JsonTokenType[] input) {
97 return Token.New( input.Select(t => (int)t).ToArray() );
97 return Token.New( input.Select(t => (int)t).ToArray() );
98 }
98 }
99
99
100 static ParserContext CreateParserContext(Token expr, JSONElementContext context) {
100 static ParserContext CreateParserContext(Token expr, JsonElementContext context) {
101
101
102 var dfa = new DFATable();
102 var dfa = new DFATable();
103 var builder = new RegularExpressionVisitor(dfa);
103 var builder = new RegularExpressionVisitor(dfa);
104 expr.Accept(builder);
104 expr.Accept(builder);
105 builder.BuildDFA();
105 builder.BuildDFA();
106
106
107 return new ParserContext(dfa.CreateTransitionTable(), dfa.InitialState, context);
107 return new ParserContext(dfa.CreateTransitionTable(), dfa.InitialState, context);
108 }
108 }
109
109
110 #endregion
110 #endregion
111
111
112 readonly JSONScanner m_scanner;
112 readonly JsonScanner m_scanner;
113 // json starts from the value context and may content even a single literal
113 // json starts from the value context and may content even a single literal
114 MemberContext m_memberContext = MemberContext.MemberValue;
114 MemberContext m_memberContext = MemberContext.MemberValue;
115
115
116 JSONElementType m_elementType;
116 JsonElementType m_elementType;
117 object m_elementValue;
117 object m_elementValue;
118 string m_memberName = String.Empty;
118 string m_memberName = String.Empty;
119
119
120 Stack<ParserContext> m_stack = new Stack<ParserContext>();
120 Stack<ParserContext> m_stack = new Stack<ParserContext>();
121 ParserContext m_context = _jsonContext;
121 ParserContext m_context = _jsonContext;
122
122
123 /// <summary>
123 /// <summary>
124 /// Создает новый парсер на основе строки, содержащей JSON
124 /// Создает новый парсер на основе строки, содержащей JSON
125 /// </summary>
125 /// </summary>
126 /// <param name="text"></param>
126 /// <param name="text"></param>
127 public JSONParser(string text) {
127 public JsonParser(string text) {
128 Safe.ArgumentNotEmpty(text, "text");
128 Safe.ArgumentNotEmpty(text, "text");
129 m_scanner = new JSONScanner(text);
129 m_scanner = JsonStringScanner.Create(text);
130 }
130 }
131
131
132 /// <summary>
132 /// <summary>
133 /// Создает новый экземпляр парсера, на основе текстового потока.
133 /// Создает новый экземпляр парсера, на основе текстового потока.
134 /// </summary>
134 /// </summary>
135 /// <param name="reader">Текстовый поток.</param>
135 /// <param name="reader">Текстовый поток.</param>
136 public JSONParser(TextReader reader) {
136 public JsonParser(TextReader reader) {
137 Safe.ArgumentNotNull(reader, "reader");
137 Safe.ArgumentNotNull(reader, "reader");
138 m_scanner = new JSONScanner(reader);
138 m_scanner = JsonTextScanner.Create(reader);
139 }
139 }
140
140
141 public int Level {
141 public int Level {
142 get { return m_stack.Count; }
142 get { return m_stack.Count; }
143 }
143 }
144
144
145 /// <summary>
145 /// <summary>
146 /// Тип текущего элемента на котором стоит парсер.
146 /// Тип текущего элемента на котором стоит парсер.
147 /// </summary>
147 /// </summary>
148 public JSONElementType ElementType {
148 public JsonElementType ElementType {
149 get { return m_elementType; }
149 get { return m_elementType; }
150 }
150 }
151
151
152 /// <summary>
152 /// <summary>
153 /// Имя элемента - имя свойства родительского контейнера. Для элементов массивов и корневого всегда
153 /// Имя элемента - имя свойства родительского контейнера. Для элементов массивов и корневого всегда
154 /// пустая строка.
154 /// пустая строка.
155 /// </summary>
155 /// </summary>
156 public string ElementName {
156 public string ElementName {
157 get { return m_memberName; }
157 get { return m_memberName; }
158 }
158 }
159
159
160 /// <summary>
160 /// <summary>
161 /// Значение элемента. Только для элементов типа <see cref="JSONElementType.Value"/>, для остальных <c>null</c>
161 /// Значение элемента. Только для элементов типа <see cref="JsonElementType.Value"/>, для остальных <c>null</c>
162 /// </summary>
162 /// </summary>
163 public object ElementValue {
163 public object ElementValue {
164 get { return m_elementValue; }
164 get { return m_elementValue; }
165 }
165 }
166
166
167 /// <summary>
167 /// <summary>
168 /// Читает слеюудущий объект из потока
168 /// Читает слеюудущий объект из потока
169 /// </summary>
169 /// </summary>
170 /// <returns><c>true</c> - операция чтения прошла успешно, <c>false</c> - конец данных</returns>
170 /// <returns><c>true</c> - операция чтения прошла успешно, <c>false</c> - конец данных</returns>
171 public bool Read() {
171 public bool Read() {
172 object tokenValue;
172 object tokenValue;
173 JsonTokenType tokenType;
173 JsonTokenType tokenType;
174
174
175 m_memberName = String.Empty;
175 m_memberName = String.Empty;
176
176
177 while (m_scanner.ReadToken(out tokenValue, out tokenType)) {
177 while (m_scanner.ReadToken(out tokenValue, out tokenType)) {
178 if(!m_context.Move(tokenType))
178 if(!m_context.Move(tokenType))
179 UnexpectedToken(tokenValue, tokenType);
179 UnexpectedToken(tokenValue, tokenType);
180
180
181 switch (tokenType) {
181 switch (tokenType) {
182 case JsonTokenType.BeginObject:
182 case JsonTokenType.BeginObject:
183 m_stack.Push(m_context);
183 m_stack.Push(m_context);
184 m_context = _objectContext;
184 m_context = _objectContext;
185
185
186 m_elementValue = null;
186 m_elementValue = null;
187 m_memberContext = MemberContext.MemberName;
187 m_memberContext = MemberContext.MemberName;
188 m_elementType = JSONElementType.BeginObject;
188 m_elementType = JsonElementType.BeginObject;
189 return true;
189 return true;
190 case JsonTokenType.EndObject:
190 case JsonTokenType.EndObject:
191 if (m_stack.Count == 0)
191 if (m_stack.Count == 0)
192 UnexpectedToken(tokenValue, tokenType);
192 UnexpectedToken(tokenValue, tokenType);
193 m_context = m_stack.Pop();
193 m_context = m_stack.Pop();
194
194
195 m_elementValue = null;
195 m_elementValue = null;
196 m_elementType = JSONElementType.EndObject;
196 m_elementType = JsonElementType.EndObject;
197 return true;
197 return true;
198 case JsonTokenType.BeginArray:
198 case JsonTokenType.BeginArray:
199 m_stack.Push(m_context);
199 m_stack.Push(m_context);
200 m_context = _arrayContext;
200 m_context = _arrayContext;
201
201
202 m_elementValue = null;
202 m_elementValue = null;
203 m_memberContext = MemberContext.MemberValue;
203 m_memberContext = MemberContext.MemberValue;
204 m_elementType = JSONElementType.BeginArray;
204 m_elementType = JsonElementType.BeginArray;
205 return true;
205 return true;
206 case JsonTokenType.EndArray:
206 case JsonTokenType.EndArray:
207 if (m_stack.Count == 0)
207 if (m_stack.Count == 0)
208 UnexpectedToken(tokenValue, tokenType);
208 UnexpectedToken(tokenValue, tokenType);
209 m_context = m_stack.Pop();
209 m_context = m_stack.Pop();
210
210
211 m_elementValue = null;
211 m_elementValue = null;
212 m_elementType = JSONElementType.EndArray;
212 m_elementType = JsonElementType.EndArray;
213 return true;
213 return true;
214 case JsonTokenType.String:
214 case JsonTokenType.String:
215 if (m_memberContext == MemberContext.MemberName) {
215 if (m_memberContext == MemberContext.MemberName) {
216 m_memberName = (string)tokenValue;
216 m_memberName = (string)tokenValue;
217 break;
217 break;
218 }
218 }
219 m_elementType = JSONElementType.Value;
219 m_elementType = JsonElementType.Value;
220 m_elementValue = tokenValue;
220 m_elementValue = tokenValue;
221 return true;
221 return true;
222 case JsonTokenType.Number:
222 case JsonTokenType.Number:
223 m_elementType = JSONElementType.Value;
223 m_elementType = JsonElementType.Value;
224 m_elementValue = tokenValue;
224 m_elementValue = tokenValue;
225 return true;
225 return true;
226 case JsonTokenType.Literal:
226 case JsonTokenType.Literal:
227 m_elementType = JSONElementType.Value;
227 m_elementType = JsonElementType.Value;
228 m_elementValue = ParseLiteral((string)tokenValue);
228 m_elementValue = ParseLiteral((string)tokenValue);
229 return true;
229 return true;
230 case JsonTokenType.NameSeparator:
230 case JsonTokenType.NameSeparator:
231 m_memberContext = MemberContext.MemberValue;
231 m_memberContext = MemberContext.MemberValue;
232 break;
232 break;
233 case JsonTokenType.ValueSeparator:
233 case JsonTokenType.ValueSeparator:
234 m_memberContext = m_context.ElementContext == JSONElementContext.Object ? MemberContext.MemberName : MemberContext.MemberValue;
234 m_memberContext = m_context.ElementContext == JsonElementContext.Object ? MemberContext.MemberName : MemberContext.MemberValue;
235 break;
235 break;
236 default:
236 default:
237 UnexpectedToken(tokenValue, tokenType);
237 UnexpectedToken(tokenValue, tokenType);
238 break;
238 break;
239 }
239 }
240 }
240 }
241 if (m_context.ElementContext != JSONElementContext.None)
241 if (m_context.ElementContext != JsonElementContext.None)
242 throw new ParserException("Unexpedted end of data");
242 throw new ParserException("Unexpedted end of data");
243
243
244 EOF = true;
244 EOF = true;
245
245
246 return false;
246 return false;
247 }
247 }
248
248
249 object ParseLiteral(string literal) {
249 object ParseLiteral(string literal) {
250 switch (literal) {
250 switch (literal) {
251 case "null":
251 case "null":
252 return null;
252 return null;
253 case "false":
253 case "false":
254 return false;
254 return false;
255 case "true":
255 case "true":
256 return true;
256 return true;
257 default:
257 default:
258 UnexpectedToken(literal, JsonTokenType.Literal);
258 UnexpectedToken(literal, JsonTokenType.Literal);
259 return null; // avoid compliler error
259 return null; // avoid compliler error
260 }
260 }
261 }
261 }
262
262
263 void UnexpectedToken(object value, JsonTokenType tokenType) {
263 void UnexpectedToken(object value, JsonTokenType tokenType) {
264 throw new ParserException(String.Format("Unexpected token {0}: '{1}'", tokenType, value));
264 throw new ParserException(String.Format("Unexpected token {0}: '{1}'", tokenType, value));
265 }
265 }
266
266
267
267
268 /// <summary>
268 /// <summary>
269 /// Признак конца потока
269 /// Признак конца потока
270 /// </summary>
270 /// </summary>
271 public bool EOF {
271 public bool EOF {
272 get;
272 get;
273 private set;
273 private set;
274 }
274 }
275
275
276 protected override void Dispose(bool disposing) {
276 protected override void Dispose(bool disposing) {
277 if (disposing)
277 if (disposing)
278 m_scanner.Dispose();
278 m_scanner.Dispose();
279 }
279 }
280
280
281 /// <summary>
281 /// <summary>
282 /// Переходит в конец текущего объекта.
282 /// Переходит в конец текущего объекта.
283 /// </summary>
283 /// </summary>
284 public void SeekElementEnd() {
284 public void SeekElementEnd() {
285 var level = Level - 1;
285 var level = Level - 1;
286
286
287 Debug.Assert(level >= 0);
287 Debug.Assert(level >= 0);
288
288
289 while (Level != level)
289 while (Level != level)
290 Read();
290 Read();
291 }
291 }
292 }
292 }
293
293
294 }
294 }
@@ -1,109 +1,134
1 using System;
1 using System;
2 using System.Globalization;
2 using System.Globalization;
3 using Implab.Automaton;
3 using Implab.Automaton;
4 using System.Text;
4 using System.Text;
5 using Implab.Components;
5 using Implab.Components;
6 using System.IO;
6 using System.IO;
7
7
8 namespace Implab.Formats.JSON {
8 namespace Implab.Formats.Json {
9 /// <summary>
9 /// <summary>
10 /// Сканнер (лексер), разбивающий поток символов на токены JSON.
10 /// Сканнер (лексер), разбивающий поток символов на токены JSON.
11 /// </summary>
11 /// </summary>
12 public class JSONScanner : Disposable {
12 public abstract class JsonScanner : Disposable {
13 readonly StringBuilder m_builder = new StringBuilder();
13 readonly InputScanner<JsonGrammar.TokenType> m_jsonContext = JsonGrammar.CreateJsonExpressionScanner();
14
14 readonly InputScanner<JsonGrammar.TokenType> m_stringContext = JsonGrammar.CreateStringExpressionScanner();
15 readonly ScannerContext<JSONGrammar.TokenType> m_jsonContext = JSONGrammar.Instance.JsonExpression;
16 readonly ScannerContext<JSONGrammar.TokenType> m_stringContext = JSONGrammar.Instance.JsonStringExpression;
17
18
15
19 readonly TextScanner m_scanner;
16 readonly char[] m_unescapeBuf = new char[4];
17 readonly char[] m_buffer;
18 int m_length;
19 int m_pos;
20 readonly StringBuilder m_tokenBuilder = new StringBuilder();
20
21
21 /// <summary>
22 protected JsonScanner(char[] buffer, int pos, int length) {
22 /// Создает новый экземпляр сканнера
23 m_buffer = buffer;
23 /// </summary>
24 m_pos = pos;
24 public JSONScanner(string text) {
25 m_length = length;
25 Safe.ArgumentNotEmpty(text, "text");
26
27 m_scanner = new StringScanner(text);
28 }
26 }
29
27
30 public JSONScanner(TextReader reader, int bufferMax, int chunkSize) {
28 bool Read(InputScanner<JsonGrammar.TokenType> scanner, out JsonGrammar.TokenType tokenType) {
31 Safe.ArgumentNotNull(reader, "reader");
29 scanner.Reset();
32
30
33 m_scanner = new ReaderScanner(reader, bufferMax, chunkSize);
31 if (m_pos == m_length) {
32 m_pos = 0;
33 m_length = Read(m_buffer, 0, m_buffer.Length);
34 if (m_length == 0) {
35 tokenType = JsonGrammar.TokenType.None;
36 return false; // EOF
37 }
38 }
39
40 while(scanner.Scan(m_buffer, m_pos, m_length - m_pos)) {
41 m_tokenBuilder.Append(m_buffer, m_pos, m_length - m_pos);
42 m_pos = 0;
43 m_length = Read(m_buffer, 0, m_buffer.Length);
44 }
45 var scannerPos = scanner.Position;
46 if (scannerPos != m_pos) {
47 m_tokenBuilder.Append(m_buffer, m_pos, scannerPos - m_pos);
48 m_pos = scannerPos;
49 }
50
51 if (!scanner.IsFinal) {
52 if (m_length == 0) {
53 // unexpected EOF
54 throw new ParserException("Unexpected EOF");
55 } else {
56 // unecpected character
57 throw new ParserException($"Unexpected character '{m_buffer[m_pos + 1]}'");
58 }
59 }
60 tokenType = scanner.Tag;
61 return true;
34 }
62 }
35
63
36 public JSONScanner(TextReader reader) : this(reader, 1024*1024, 1024){
64 protected abstract int Read(char[] buffer, int offset, int size);
37 }
65
38
66
39 /// <summary>
67 /// <summary>
40 /// Читает следующий лексический элемент из входных данных.
68 /// Читает следующий лексический элемент из входных данных.
41 /// </summary>
69 /// </summary>
42 /// <param name="tokenValue">Возвращает значение прочитанного токена.</param>
70 /// <param name="tokenValue">Возвращает значение прочитанного токена.</param>
43 /// <param name="tokenType">Возвращает тип прочитанного токена.</param>
71 /// <param name="tokenType">Возвращает тип прочитанного токена.</param>
44 /// <returns><c>true</c> - чтение произведено успешно. <c>false</c> - достигнут конец входных данных</returns>
72 /// <returns><c>true</c> - чтение произведено успешно. <c>false</c> - достигнут конец входных данных</returns>
45 /// <remarks>В случе если токен не распознается, возникает исключение. Значения токенов обрабатываются, т.е.
73 /// <remarks>В случе если токен не распознается, возникает исключение. Значения токенов обрабатываются, т.е.
46 /// в строках обрабатываются экранированные символы, числа становтся типа double.</remarks>
74 /// в строках обрабатываются экранированные символы, числа становтся типа double.</remarks>
47 public bool ReadToken(out object tokenValue, out JsonTokenType tokenType) {
75 public bool ReadToken(out object tokenValue, out JsonTokenType tokenType) {
48 JSONGrammar.TokenType[] tag;
76 JsonGrammar.TokenType tag;
49 while (m_jsonContext.Execute(m_scanner, out tag)) {
77 m_tokenBuilder.Clear();
50 switch (tag[0]) {
78 while (Read(m_jsonContext, out tag)) {
51 case JSONGrammar.TokenType.StringBound:
79 switch (tag) {
80 case JsonGrammar.TokenType.StringBound:
52 tokenValue = ReadString();
81 tokenValue = ReadString();
53 tokenType = JsonTokenType.String;
82 tokenType = JsonTokenType.String;
54 break;
83 break;
55 case JSONGrammar.TokenType.Number:
84 case JsonGrammar.TokenType.Number:
56 tokenValue = Double.Parse(m_scanner.GetTokenValue(), CultureInfo.InvariantCulture);
85 tokenValue = Double.Parse(m_tokenBuilder.ToString(), CultureInfo.InvariantCulture);
57 tokenType = JsonTokenType.Number;
86 tokenType = JsonTokenType.Number;
58 break;
87 break;
59 case JSONGrammar.TokenType.Whitespace:
88 case JsonGrammar.TokenType.Literal:
89 tokenType = JsonTokenType.Literal;
90 tokenValue = m_tokenBuilder.ToString();
91 break;
92 case JsonGrammar.TokenType.Whitespace:
93 m_tokenBuilder.Clear();
60 continue;
94 continue;
61 default:
95 default:
62 tokenType = (JsonTokenType)tag[0];
96 tokenType = (JsonTokenType)tag;
63 tokenValue = m_scanner.GetTokenValue();
97 tokenValue = null;
64 break;
98 break;
65 }
99 }
66 return true;
100 return true;
67 }
101 }
68 tokenValue = null;
102 tokenValue = null;
69 tokenType = JsonTokenType.None;
103 tokenType = JsonTokenType.None;
70 return false;
104 return false;
71 }
105 }
72
106
73 string ReadString() {
107 string ReadString() {
74 int pos = 0;
108 JsonGrammar.TokenType tag;
75 var buf = new char[6]; // the buffer for unescaping chars
109 m_tokenBuilder.Clear();
76
77 JSONGrammar.TokenType[] tag;
78 m_builder.Clear();
79
110
80 while (m_stringContext.Execute(m_scanner, out tag)) {
111 while (Read(m_stringContext, out tag)) {
81 switch (tag[0]) {
112 switch (tag) {
82 case JSONGrammar.TokenType.StringBound:
113 case JsonGrammar.TokenType.StringBound:
83 return m_builder.ToString();
114 m_tokenBuilder.Length--;
84 case JSONGrammar.TokenType.UnescapedChar:
115 return m_tokenBuilder.ToString();
85 m_scanner.CopyTokenTo(m_builder);
116 case JsonGrammar.TokenType.UnescapedChar:
86 break;
117 break;
87 case JSONGrammar.TokenType.EscapedUnicode: // \xXXXX - unicode escape sequence
118 case JsonGrammar.TokenType.EscapedUnicode: // \xXXXX - unicode escape sequence
88 m_scanner.CopyTokenTo(buf, 0);
119 m_tokenBuilder.CopyTo(m_tokenBuilder.Length - 4, m_unescapeBuf, 0, 4);
89 m_builder.Append(StringTranslator.TranslateHexUnicode(buf, 2));
120 m_tokenBuilder.Length -= 6;
90 pos++;
121 m_tokenBuilder.Append(StringTranslator.TranslateHexUnicode(m_unescapeBuf, 0));
91 break;
122 break;
92 case JSONGrammar.TokenType.EscapedChar: // \t - escape sequence
123 case JsonGrammar.TokenType.EscapedChar: // \t - escape sequence
93 m_scanner.CopyTokenTo(buf, 0);
124 var ch = m_tokenBuilder[m_tokenBuilder.Length-1];
94 m_builder.Append(StringTranslator.TranslateEscapedChar(buf[1]));
125 m_tokenBuilder.Length -= 2;
126 m_tokenBuilder.Append(StringTranslator.TranslateEscapedChar(ch));
95 break;
127 break;
96 }
128 }
97
98 }
129 }
99
130
100 throw new ParserException("Unexpected end of data");
131 throw new ParserException("Unexpected end of data");
101 }
132 }
102
103 protected override void Dispose(bool disposing) {
104 if (disposing)
105 m_scanner.Dispose();
106 base.Dispose(disposing);
107 }
108 }
133 }
109 }
134 }
@@ -1,44 +1,44
1 namespace Implab.Formats.JSON {
1 namespace Implab.Formats.Json {
2 /// <summary>
2 /// <summary>
3 /// Тип токенов, возвращаемых <see cref="JSONScanner"/>.
3 /// Тип токенов, возвращаемых <see cref="JsonScanner"/>.
4 /// </summary>
4 /// </summary>
5 public enum JsonTokenType : int {
5 public enum JsonTokenType : int {
6 None = 0,
6 None = 0,
7 /// <summary>
7 /// <summary>
8 /// Начало объекта
8 /// Начало объекта
9 /// </summary>
9 /// </summary>
10 BeginObject,
10 BeginObject,
11 /// <summary>
11 /// <summary>
12 /// Конец объекта
12 /// Конец объекта
13 /// </summary>
13 /// </summary>
14 EndObject,
14 EndObject,
15 /// <summary>
15 /// <summary>
16 /// Начало массива
16 /// Начало массива
17 /// </summary>
17 /// </summary>
18 BeginArray,
18 BeginArray,
19 /// <summary>
19 /// <summary>
20 /// Конец массива
20 /// Конец массива
21 /// </summary>
21 /// </summary>
22 EndArray,
22 EndArray,
23 /// <summary>
23 /// <summary>
24 /// Строка
24 /// Строка
25 /// </summary>
25 /// </summary>
26 String,
26 String,
27 /// <summary>
27 /// <summary>
28 /// Число
28 /// Число
29 /// </summary>
29 /// </summary>
30 Number,
30 Number,
31 /// <summary>
31 /// <summary>
32 /// Литерал
32 /// Литерал
33 /// </summary>
33 /// </summary>
34 Literal,
34 Literal,
35 /// <summary>
35 /// <summary>
36 /// Разделитель имени <c>:</c>
36 /// Разделитель имени <c>:</c>
37 /// </summary>
37 /// </summary>
38 NameSeparator,
38 NameSeparator,
39 /// <summary>
39 /// <summary>
40 /// Разделитель имени <c>,</c>
40 /// Разделитель имени <c>,</c>
41 /// </summary>
41 /// </summary>
42 ValueSeparator
42 ValueSeparator
43 }
43 }
44 }
44 }
@@ -1,319 +1,319
1 using System;
1 using System;
2 using System.Collections.Generic;
2 using System.Collections.Generic;
3 using System.IO;
3 using System.IO;
4 using System.Globalization;
4 using System.Globalization;
5 using System.Diagnostics;
5 using System.Diagnostics;
6
6
7 namespace Implab.Formats.JSON {
7 namespace Implab.Formats.Json {
8 public class JSONWriter {
8 public class JsonWriter {
9 struct Context {
9 struct Context {
10 public bool needComma;
10 public bool needComma;
11 public JSONElementContext element;
11 public JsonElementContext element;
12 }
12 }
13 Stack<Context> m_contextStack = new Stack<Context>();
13 Stack<Context> m_contextStack = new Stack<Context>();
14 Context m_context;
14 Context m_context;
15
15
16 const int BUFFER_SIZE = 64;
16 const int BUFFER_SIZE = 64;
17
17
18 TextWriter m_writer;
18 TextWriter m_writer;
19 readonly bool m_indent = true;
19 readonly bool m_indent = true;
20 readonly int m_indentSize = 4;
20 readonly int m_indentSize = 4;
21 readonly char[] m_buffer = new char[BUFFER_SIZE];
21 readonly char[] m_buffer = new char[BUFFER_SIZE];
22 int m_bufferPos;
22 int m_bufferPos;
23
23
24 static readonly char [] _hex = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' };
24 static readonly char [] _hex = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' };
25 static readonly char [] _escapeBKS,
25 static readonly char [] _escapeBKS,
26 _escapeFWD,
26 _escapeFWD,
27 _escapeCR,
27 _escapeCR,
28 _escapeNL,
28 _escapeNL,
29 _escapeTAB,
29 _escapeTAB,
30 _escapeBSLASH,
30 _escapeBSLASH,
31 _escapeQ;
31 _escapeQ;
32
32
33 static JSONWriter() {
33 static JsonWriter() {
34 _escapeBKS = "\\b".ToCharArray();
34 _escapeBKS = "\\b".ToCharArray();
35 _escapeFWD = "\\f".ToCharArray();
35 _escapeFWD = "\\f".ToCharArray();
36 _escapeCR = "\\r".ToCharArray();
36 _escapeCR = "\\r".ToCharArray();
37 _escapeNL = "\\n".ToCharArray();
37 _escapeNL = "\\n".ToCharArray();
38 _escapeTAB = "\\t".ToCharArray();
38 _escapeTAB = "\\t".ToCharArray();
39 _escapeBSLASH = "\\\\".ToCharArray();
39 _escapeBSLASH = "\\\\".ToCharArray();
40 _escapeQ = "\\\"".ToCharArray();
40 _escapeQ = "\\\"".ToCharArray();
41 }
41 }
42
42
43 public JSONWriter(TextWriter writer) {
43 public JsonWriter(TextWriter writer) {
44 Safe.ArgumentNotNull(writer, "writer");
44 Safe.ArgumentNotNull(writer, "writer");
45 m_writer = writer;
45 m_writer = writer;
46 }
46 }
47
47
48 public JSONWriter(TextWriter writer, bool indent) {
48 public JsonWriter(TextWriter writer, bool indent) {
49 Safe.ArgumentNotNull(writer, "writer");
49 Safe.ArgumentNotNull(writer, "writer");
50
50
51 m_writer = writer;
51 m_writer = writer;
52 m_indent = indent;
52 m_indent = indent;
53 }
53 }
54
54
55 void WriteIndent() {
55 void WriteIndent() {
56 if (m_indent) {
56 if (m_indent) {
57 var indent = new char[m_contextStack.Count * m_indentSize + 1];
57 var indent = new char[m_contextStack.Count * m_indentSize + 1];
58 indent[0] = '\n';
58 indent[0] = '\n';
59 for (int i = 1; i < indent.Length; i++)
59 for (int i = 1; i < indent.Length; i++)
60 indent[i] = ' ';
60 indent[i] = ' ';
61 m_writer.Write(new String(indent));
61 m_writer.Write(new String(indent));
62 } else {
62 } else {
63 m_writer.Write(' ');
63 m_writer.Write(' ');
64 }
64 }
65 }
65 }
66
66
67 void WriteMemberName(string name) {
67 void WriteMemberName(string name) {
68 Safe.ArgumentNotEmpty(name, "name");
68 Safe.ArgumentNotEmpty(name, "name");
69 if (m_context.element != JSONElementContext.Object)
69 if (m_context.element != JsonElementContext.Object)
70 OperationNotApplicable("WriteMember");
70 OperationNotApplicable("WriteMember");
71 if (m_context.needComma)
71 if (m_context.needComma)
72 m_writer.Write(",");
72 m_writer.Write(",");
73
73
74 WriteIndent();
74 WriteIndent();
75 m_context.needComma = true;
75 m_context.needComma = true;
76 Write(name);
76 Write(name);
77 m_writer.Write(" : ");
77 m_writer.Write(" : ");
78 }
78 }
79
79
80 public void WriteValue(string name, string value) {
80 public void WriteValue(string name, string value) {
81 WriteMemberName(name);
81 WriteMemberName(name);
82 Write(value);
82 Write(value);
83 }
83 }
84
84
85 public void WriteValue(string name, bool value) {
85 public void WriteValue(string name, bool value) {
86 WriteMemberName(name);
86 WriteMemberName(name);
87 Write(value);
87 Write(value);
88 }
88 }
89
89
90 public void WriteValue(string name, double value) {
90 public void WriteValue(string name, double value) {
91 WriteMemberName(name);
91 WriteMemberName(name);
92 Write(value);
92 Write(value);
93 }
93 }
94
94
95 public void WriteValue(string value) {
95 public void WriteValue(string value) {
96 if (m_context.element == JSONElementContext.Array) {
96 if (m_context.element == JsonElementContext.Array) {
97
97
98 if (m_context.needComma)
98 if (m_context.needComma)
99 m_writer.Write(",");
99 m_writer.Write(",");
100 WriteIndent();
100 WriteIndent();
101 m_context.needComma = true;
101 m_context.needComma = true;
102
102
103 Write(value);
103 Write(value);
104 } else if (m_context.element == JSONElementContext.None) {
104 } else if (m_context.element == JsonElementContext.None) {
105 Write(value);
105 Write(value);
106 m_context.element = JSONElementContext.Closed;
106 m_context.element = JsonElementContext.Closed;
107 } else {
107 } else {
108 OperationNotApplicable("WriteValue");
108 OperationNotApplicable("WriteValue");
109 }
109 }
110 }
110 }
111
111
112 public void WriteValue(bool value) {
112 public void WriteValue(bool value) {
113 if (m_context.element == JSONElementContext.Array) {
113 if (m_context.element == JsonElementContext.Array) {
114
114
115 if (m_context.needComma)
115 if (m_context.needComma)
116 m_writer.Write(",");
116 m_writer.Write(",");
117 WriteIndent();
117 WriteIndent();
118 m_context.needComma = true;
118 m_context.needComma = true;
119
119
120 Write(value);
120 Write(value);
121 } else if (m_context.element == JSONElementContext.None) {
121 } else if (m_context.element == JsonElementContext.None) {
122 Write(value);
122 Write(value);
123 m_context.element = JSONElementContext.Closed;
123 m_context.element = JsonElementContext.Closed;
124 } else {
124 } else {
125 OperationNotApplicable("WriteValue");
125 OperationNotApplicable("WriteValue");
126 }
126 }
127 }
127 }
128
128
129 public void WriteValue(double value) {
129 public void WriteValue(double value) {
130 if (m_context.element == JSONElementContext.Array) {
130 if (m_context.element == JsonElementContext.Array) {
131
131
132 if (m_context.needComma)
132 if (m_context.needComma)
133 m_writer.Write(",");
133 m_writer.Write(",");
134 WriteIndent();
134 WriteIndent();
135 m_context.needComma = true;
135 m_context.needComma = true;
136
136
137 Write(value);
137 Write(value);
138 } else if (m_context.element == JSONElementContext.None) {
138 } else if (m_context.element == JsonElementContext.None) {
139 Write(value);
139 Write(value);
140 m_context.element = JSONElementContext.Closed;
140 m_context.element = JsonElementContext.Closed;
141 } else {
141 } else {
142 OperationNotApplicable("WriteValue");
142 OperationNotApplicable("WriteValue");
143 }
143 }
144 }
144 }
145
145
146 public void BeginObject() {
146 public void BeginObject() {
147 if (m_context.element != JSONElementContext.None && m_context.element != JSONElementContext.Array)
147 if (m_context.element != JsonElementContext.None && m_context.element != JsonElementContext.Array)
148 OperationNotApplicable("BeginObject");
148 OperationNotApplicable("BeginObject");
149 if (m_context.needComma)
149 if (m_context.needComma)
150 m_writer.Write(",");
150 m_writer.Write(",");
151
151
152 WriteIndent();
152 WriteIndent();
153
153
154 m_context.needComma = true;
154 m_context.needComma = true;
155
155
156 m_contextStack.Push(m_context);
156 m_contextStack.Push(m_context);
157
157
158 m_context = new Context { element = JSONElementContext.Object, needComma = false };
158 m_context = new Context { element = JsonElementContext.Object, needComma = false };
159 m_writer.Write("{");
159 m_writer.Write("{");
160 }
160 }
161
161
162 public void BeginObject(string name) {
162 public void BeginObject(string name) {
163 WriteMemberName(name);
163 WriteMemberName(name);
164
164
165 m_contextStack.Push(m_context);
165 m_contextStack.Push(m_context);
166
166
167 m_context = new Context { element = JSONElementContext.Object, needComma = false };
167 m_context = new Context { element = JsonElementContext.Object, needComma = false };
168 m_writer.Write("{");
168 m_writer.Write("{");
169 }
169 }
170
170
171 public void EndObject() {
171 public void EndObject() {
172 if (m_context.element != JSONElementContext.Object)
172 if (m_context.element != JsonElementContext.Object)
173 OperationNotApplicable("EndObject");
173 OperationNotApplicable("EndObject");
174
174
175 m_context = m_contextStack.Pop();
175 m_context = m_contextStack.Pop();
176 if (m_contextStack.Count == 0)
176 if (m_contextStack.Count == 0)
177 m_context.element = JSONElementContext.Closed;
177 m_context.element = JsonElementContext.Closed;
178 WriteIndent();
178 WriteIndent();
179 m_writer.Write("}");
179 m_writer.Write("}");
180 }
180 }
181
181
182 public void BeginArray() {
182 public void BeginArray() {
183 if (m_context.element != JSONElementContext.None && m_context.element != JSONElementContext.Array)
183 if (m_context.element != JsonElementContext.None && m_context.element != JsonElementContext.Array)
184 throw new InvalidOperationException();
184 throw new InvalidOperationException();
185 if (m_context.needComma) {
185 if (m_context.needComma) {
186 m_writer.Write(",");
186 m_writer.Write(",");
187
187
188 }
188 }
189 m_context.needComma = true;
189 m_context.needComma = true;
190
190
191 WriteIndent();
191 WriteIndent();
192 m_contextStack.Push(m_context);
192 m_contextStack.Push(m_context);
193 m_context = new Context { element = JSONElementContext.Array, needComma = false };
193 m_context = new Context { element = JsonElementContext.Array, needComma = false };
194 m_writer.Write("[");
194 m_writer.Write("[");
195 }
195 }
196
196
197 public void BeginArray(string name) {
197 public void BeginArray(string name) {
198 WriteMemberName(name);
198 WriteMemberName(name);
199
199
200 m_contextStack.Push(m_context);
200 m_contextStack.Push(m_context);
201
201
202 m_context = new Context { element = JSONElementContext.Array, needComma = false };
202 m_context = new Context { element = JsonElementContext.Array, needComma = false };
203 m_writer.Write("[");
203 m_writer.Write("[");
204 }
204 }
205
205
206 public void EndArray() {
206 public void EndArray() {
207 if (m_context.element != JSONElementContext.Array)
207 if (m_context.element != JsonElementContext.Array)
208 OperationNotApplicable("EndArray");
208 OperationNotApplicable("EndArray");
209
209
210 m_context = m_contextStack.Pop();
210 m_context = m_contextStack.Pop();
211 if (m_contextStack.Count == 0)
211 if (m_contextStack.Count == 0)
212 m_context.element = JSONElementContext.Closed;
212 m_context.element = JsonElementContext.Closed;
213 WriteIndent();
213 WriteIndent();
214 m_writer.Write("]");
214 m_writer.Write("]");
215 }
215 }
216
216
217 void Write(bool value) {
217 void Write(bool value) {
218 m_writer.Write(value ? "true" : "false");
218 m_writer.Write(value ? "true" : "false");
219 }
219 }
220
220
221 void FlushBuffer() {
221 void FlushBuffer() {
222 if (m_bufferPos > 0) {
222 if (m_bufferPos > 0) {
223 m_writer.Write(m_buffer, 0, m_bufferPos);
223 m_writer.Write(m_buffer, 0, m_bufferPos);
224 m_bufferPos = 0;
224 m_bufferPos = 0;
225 }
225 }
226 }
226 }
227
227
228 void Write(string value) {
228 void Write(string value) {
229 if (value == null) {
229 if (value == null) {
230 m_writer.Write("null");
230 m_writer.Write("null");
231 return;
231 return;
232 }
232 }
233
233
234 Debug.Assert(m_bufferPos == 0);
234 Debug.Assert(m_bufferPos == 0);
235
235
236 var chars = value.ToCharArray();
236 var chars = value.ToCharArray();
237 m_buffer[m_bufferPos++] = '"';
237 m_buffer[m_bufferPos++] = '"';
238
238
239 // Analysis disable once ForCanBeConvertedToForeach
239 // Analysis disable once ForCanBeConvertedToForeach
240 for (int i = 0; i < chars.Length; i++) {
240 for (int i = 0; i < chars.Length; i++) {
241 var ch = chars[i];
241 var ch = chars[i];
242
242
243 char[] escapeSeq;
243 char[] escapeSeq;
244
244
245 switch (ch) {
245 switch (ch) {
246 case '\b':
246 case '\b':
247 escapeSeq = _escapeBKS;
247 escapeSeq = _escapeBKS;
248 break;
248 break;
249 case '\f':
249 case '\f':
250 escapeSeq = _escapeFWD;
250 escapeSeq = _escapeFWD;
251 break;
251 break;
252 case '\r':
252 case '\r':
253 escapeSeq = _escapeCR;
253 escapeSeq = _escapeCR;
254 break;
254 break;
255 case '\n':
255 case '\n':
256 escapeSeq = _escapeNL;
256 escapeSeq = _escapeNL;
257 break;
257 break;
258 case '\t':
258 case '\t':
259 escapeSeq = _escapeTAB;
259 escapeSeq = _escapeTAB;
260 break;
260 break;
261 case '\\':
261 case '\\':
262 escapeSeq = _escapeBSLASH;
262 escapeSeq = _escapeBSLASH;
263 break;
263 break;
264 case '"':
264 case '"':
265 escapeSeq = _escapeQ;
265 escapeSeq = _escapeQ;
266 break;
266 break;
267 default:
267 default:
268 if (ch < 0x20) {
268 if (ch < 0x20) {
269 if (m_bufferPos + 6 > BUFFER_SIZE)
269 if (m_bufferPos + 6 > BUFFER_SIZE)
270 FlushBuffer();
270 FlushBuffer();
271
271
272 m_buffer[m_bufferPos++] = '\\';
272 m_buffer[m_bufferPos++] = '\\';
273 m_buffer[m_bufferPos++] = 'u';
273 m_buffer[m_bufferPos++] = 'u';
274 m_buffer[m_bufferPos++] = '0';
274 m_buffer[m_bufferPos++] = '0';
275 m_buffer[m_bufferPos++] = '0';
275 m_buffer[m_bufferPos++] = '0';
276 m_buffer[m_bufferPos++] = _hex[ch >> 4 & 0xf];
276 m_buffer[m_bufferPos++] = _hex[ch >> 4 & 0xf];
277 m_buffer[m_bufferPos++] = _hex[ch & 0xf];
277 m_buffer[m_bufferPos++] = _hex[ch & 0xf];
278
278
279 } else {
279 } else {
280 if (m_bufferPos >= BUFFER_SIZE)
280 if (m_bufferPos >= BUFFER_SIZE)
281 FlushBuffer();
281 FlushBuffer();
282 m_buffer[m_bufferPos++] = ch;
282 m_buffer[m_bufferPos++] = ch;
283 }
283 }
284 continue;
284 continue;
285 }
285 }
286
286
287 if (m_bufferPos + escapeSeq.Length > BUFFER_SIZE)
287 if (m_bufferPos + escapeSeq.Length > BUFFER_SIZE)
288 FlushBuffer();
288 FlushBuffer();
289
289
290 Array.Copy(escapeSeq, 0, m_buffer, m_bufferPos, escapeSeq.Length);
290 Array.Copy(escapeSeq, 0, m_buffer, m_bufferPos, escapeSeq.Length);
291 m_bufferPos += escapeSeq.Length;
291 m_bufferPos += escapeSeq.Length;
292
292
293 }
293 }
294
294
295 if (m_bufferPos >= BUFFER_SIZE)
295 if (m_bufferPos >= BUFFER_SIZE)
296 FlushBuffer();
296 FlushBuffer();
297
297
298 m_buffer[m_bufferPos++] = '"';
298 m_buffer[m_bufferPos++] = '"';
299
299
300 FlushBuffer();
300 FlushBuffer();
301 }
301 }
302
302
303 void Write(double value) {
303 void Write(double value) {
304 if (double.IsNaN(value))
304 if (double.IsNaN(value))
305 Write("NaN");
305 Write("NaN");
306 else if (double.IsNegativeInfinity(value))
306 else if (double.IsNegativeInfinity(value))
307 Write("-Infinity");
307 Write("-Infinity");
308 else if (double.IsPositiveInfinity(value))
308 else if (double.IsPositiveInfinity(value))
309 Write("Infinity");
309 Write("Infinity");
310 else
310 else
311 m_writer.Write(value.ToString(CultureInfo.InvariantCulture));
311 m_writer.Write(value.ToString(CultureInfo.InvariantCulture));
312 }
312 }
313
313
314 void OperationNotApplicable(string opName) {
314 void OperationNotApplicable(string opName) {
315 throw new InvalidOperationException(String.Format("The operation '{0}' isn't applicable in the context of '{1}'", opName, m_context.element ));
315 throw new InvalidOperationException(String.Format("The operation '{0}' isn't applicable in the context of '{1}'", opName, m_context.element ));
316 }
316 }
317
317
318 }
318 }
319 }
319 }
@@ -1,52 +1,52
1 using Implab;
1 using Implab;
2 using Implab.Formats;
2 using Implab.Formats;
3 using System;
3 using System;
4 using System.Collections.Generic;
4 using System.Collections.Generic;
5 using System.Diagnostics;
5 using System.Diagnostics;
6 using System.Linq;
6 using System.Linq;
7 using System.Text;
7 using System.Text;
8 using System.Threading.Tasks;
8 using System.Threading.Tasks;
9
9
10 namespace Implab.Formats.JSON {
10 namespace Implab.Formats.Json {
11 /// <summary>
11 /// <summary>
12 /// Класс для преобразования экранированной строки JSON
12 /// Класс для преобразования экранированной строки JSON
13 /// </summary>
13 /// </summary>
14 static class StringTranslator {
14 static class StringTranslator {
15 static readonly char[] _escMap;
15 static readonly char[] _escMap;
16 static readonly int[] _hexMap;
16 static readonly int[] _hexMap;
17
17
18 static StringTranslator() {
18 static StringTranslator() {
19 var chars = new char[] { 'b', 'f', 't', 'r', 'n', '\\', '/', '"' };
19 var chars = new char[] { 'b', 'f', 't', 'r', 'n', '\\', '/', '"' };
20 var vals = new char[] { '\b', '\f', '\t', '\r', '\n', '\\', '/', '"' };
20 var vals = new char[] { '\b', '\f', '\t', '\r', '\n', '\\', '/', '"' };
21
21
22 _escMap = new char[chars.Max() + 1];
22 _escMap = new char[chars.Max() + 1];
23
23
24 for (int i = 0; i < chars.Length; i++)
24 for (int i = 0; i < chars.Length; i++)
25 _escMap[chars[i]] = vals[i];
25 _escMap[chars[i]] = vals[i];
26
26
27 var hexs = new char[] { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f', 'A', 'B', 'C', 'D', 'E', 'F' };
27 var hexs = new char[] { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f', 'A', 'B', 'C', 'D', 'E', 'F' };
28 var ints = new int[] { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 10, 11, 12, 13, 14, 15 };
28 var ints = new int[] { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 10, 11, 12, 13, 14, 15 };
29
29
30 _hexMap = new int[hexs.Max() + 1];
30 _hexMap = new int[hexs.Max() + 1];
31
31
32 for (int i = 0; i < hexs.Length; i++)
32 for (int i = 0; i < hexs.Length; i++)
33 _hexMap[hexs[i]] = ints[i];
33 _hexMap[hexs[i]] = ints[i];
34
34
35 }
35 }
36
36
37 internal static char TranslateEscapedChar(char symbol) {
37 internal static char TranslateEscapedChar(char symbol) {
38 return _escMap[symbol];
38 return _escMap[symbol];
39 }
39 }
40
40
41 internal static char TranslateHexUnicode(char[] symbols, int offset) {
41 internal static char TranslateHexUnicode(char[] symbols, int offset) {
42 Debug.Assert(symbols != null);
42 Debug.Assert(symbols != null);
43 Debug.Assert(symbols.Length - offset >= 4);
43 Debug.Assert(symbols.Length - offset >= 4);
44
44
45 int value = (_hexMap[symbols[offset]] << 12)
45 int value = (_hexMap[symbols[offset]] << 12)
46 | (_hexMap[symbols[offset + 1]] << 8)
46 | (_hexMap[symbols[offset + 1]] << 8)
47 | (_hexMap[symbols[offset + 2]] << 4)
47 | (_hexMap[symbols[offset + 2]] << 4)
48 | (_hexMap[symbols[offset + 3]]);
48 | (_hexMap[symbols[offset + 3]]);
49 return (char)value;
49 return (char)value;
50 }
50 }
51 }
51 }
52 }
52 }
@@ -1,281 +1,279
1 <?xml version="1.0" encoding="utf-8"?>
1 <?xml version="1.0" encoding="utf-8"?>
2 <Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
2 <Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
3 <PropertyGroup>
3 <PropertyGroup>
4 <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
4 <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
5 <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
5 <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
6 <ProjectGuid>{F550F1F8-8746-4AD0-9614-855F4C4B7F05}</ProjectGuid>
6 <ProjectGuid>{F550F1F8-8746-4AD0-9614-855F4C4B7F05}</ProjectGuid>
7 <OutputType>Library</OutputType>
7 <OutputType>Library</OutputType>
8 <RootNamespace>Implab</RootNamespace>
8 <RootNamespace>Implab</RootNamespace>
9 <AssemblyName>Implab</AssemblyName>
9 <AssemblyName>Implab</AssemblyName>
10 <TargetFrameworkVersion>v4.5</TargetFrameworkVersion>
10 <TargetFrameworkVersion>v4.5</TargetFrameworkVersion>
11 </PropertyGroup>
11 </PropertyGroup>
12 <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
12 <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
13 <DebugSymbols>true</DebugSymbols>
13 <DebugSymbols>true</DebugSymbols>
14 <DebugType>full</DebugType>
14 <DebugType>full</DebugType>
15 <Optimize>false</Optimize>
15 <Optimize>false</Optimize>
16 <OutputPath>bin\Debug</OutputPath>
16 <OutputPath>bin\Debug</OutputPath>
17 <DefineConstants>TRACE;DEBUG;</DefineConstants>
17 <DefineConstants>TRACE;DEBUG;</DefineConstants>
18 <ErrorReport>prompt</ErrorReport>
18 <ErrorReport>prompt</ErrorReport>
19 <WarningLevel>4</WarningLevel>
19 <WarningLevel>4</WarningLevel>
20 <ConsolePause>false</ConsolePause>
20 <ConsolePause>false</ConsolePause>
21 <RunCodeAnalysis>true</RunCodeAnalysis>
21 <RunCodeAnalysis>true</RunCodeAnalysis>
22 </PropertyGroup>
22 </PropertyGroup>
23 <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
23 <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
24 <DebugType>full</DebugType>
24 <DebugType>full</DebugType>
25 <Optimize>true</Optimize>
25 <Optimize>true</Optimize>
26 <OutputPath>bin\Release</OutputPath>
26 <OutputPath>bin\Release</OutputPath>
27 <ErrorReport>prompt</ErrorReport>
27 <ErrorReport>prompt</ErrorReport>
28 <WarningLevel>4</WarningLevel>
28 <WarningLevel>4</WarningLevel>
29 <ConsolePause>false</ConsolePause>
29 <ConsolePause>false</ConsolePause>
30 </PropertyGroup>
30 </PropertyGroup>
31 <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug 4.5|AnyCPU' ">
31 <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug 4.5|AnyCPU' ">
32 <DebugSymbols>true</DebugSymbols>
32 <DebugSymbols>true</DebugSymbols>
33 <DebugType>full</DebugType>
33 <DebugType>full</DebugType>
34 <Optimize>false</Optimize>
34 <Optimize>false</Optimize>
35 <OutputPath>bin\Debug</OutputPath>
35 <OutputPath>bin\Debug</OutputPath>
36 <DefineConstants>TRACE;DEBUG;NET_4_5</DefineConstants>
36 <DefineConstants>TRACE;DEBUG;NET_4_5</DefineConstants>
37 <ErrorReport>prompt</ErrorReport>
37 <ErrorReport>prompt</ErrorReport>
38 <WarningLevel>4</WarningLevel>
38 <WarningLevel>4</WarningLevel>
39 <RunCodeAnalysis>true</RunCodeAnalysis>
39 <RunCodeAnalysis>true</RunCodeAnalysis>
40 <ConsolePause>false</ConsolePause>
40 <ConsolePause>false</ConsolePause>
41 </PropertyGroup>
41 </PropertyGroup>
42 <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release 4.5|AnyCPU' ">
42 <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release 4.5|AnyCPU' ">
43 <Optimize>true</Optimize>
43 <Optimize>true</Optimize>
44 <OutputPath>bin\Release</OutputPath>
44 <OutputPath>bin\Release</OutputPath>
45 <ErrorReport>prompt</ErrorReport>
45 <ErrorReport>prompt</ErrorReport>
46 <WarningLevel>4</WarningLevel>
46 <WarningLevel>4</WarningLevel>
47 <ConsolePause>false</ConsolePause>
47 <ConsolePause>false</ConsolePause>
48 <DefineConstants>NET_4_5</DefineConstants>
48 <DefineConstants>NET_4_5</DefineConstants>
49 </PropertyGroup>
49 </PropertyGroup>
50 <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'DebugMono|AnyCPU' ">
50 <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'DebugMono|AnyCPU' ">
51 <DebugSymbols>true</DebugSymbols>
51 <DebugSymbols>true</DebugSymbols>
52 <DebugType>full</DebugType>
52 <DebugType>full</DebugType>
53 <Optimize>false</Optimize>
53 <Optimize>false</Optimize>
54 <OutputPath>bin\Debug</OutputPath>
54 <OutputPath>bin\Debug</OutputPath>
55 <DefineConstants>TRACE;DEBUG;NET_4_5;MONO</DefineConstants>
55 <DefineConstants>TRACE;DEBUG;NET_4_5;MONO</DefineConstants>
56 <ErrorReport>prompt</ErrorReport>
56 <ErrorReport>prompt</ErrorReport>
57 <WarningLevel>4</WarningLevel>
57 <WarningLevel>4</WarningLevel>
58 <RunCodeAnalysis>true</RunCodeAnalysis>
58 <RunCodeAnalysis>true</RunCodeAnalysis>
59 <ConsolePause>false</ConsolePause>
59 <ConsolePause>false</ConsolePause>
60 </PropertyGroup>
60 </PropertyGroup>
61 <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'ReleaseMono|AnyCPU' ">
61 <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'ReleaseMono|AnyCPU' ">
62 <Optimize>true</Optimize>
62 <Optimize>true</Optimize>
63 <OutputPath>bin\Release</OutputPath>
63 <OutputPath>bin\Release</OutputPath>
64 <DefineConstants>NET_4_5;MONO;</DefineConstants>
64 <DefineConstants>NET_4_5;MONO;</DefineConstants>
65 <ErrorReport>prompt</ErrorReport>
65 <ErrorReport>prompt</ErrorReport>
66 <WarningLevel>4</WarningLevel>
66 <WarningLevel>4</WarningLevel>
67 <ConsolePause>false</ConsolePause>
67 <ConsolePause>false</ConsolePause>
68 </PropertyGroup>
68 </PropertyGroup>
69 <ItemGroup>
69 <ItemGroup>
70 <Reference Include="System" />
70 <Reference Include="System" />
71 <Reference Include="System.Xml" />
71 <Reference Include="System.Xml" />
72 <Reference Include="mscorlib" />
72 <Reference Include="mscorlib" />
73 </ItemGroup>
73 </ItemGroup>
74 <ItemGroup>
74 <ItemGroup>
75 <Compile Include="Components\StateChangeEventArgs.cs" />
75 <Compile Include="Components\StateChangeEventArgs.cs" />
76 <Compile Include="CustomEqualityComparer.cs" />
76 <Compile Include="CustomEqualityComparer.cs" />
77 <Compile Include="Diagnostics\ConsoleTraceListener.cs" />
77 <Compile Include="Diagnostics\ConsoleTraceListener.cs" />
78 <Compile Include="Diagnostics\LogChannel.cs" />
78 <Compile Include="Diagnostics\LogChannel.cs" />
79 <Compile Include="Diagnostics\LogicalOperation.cs" />
79 <Compile Include="Diagnostics\LogicalOperation.cs" />
80 <Compile Include="Diagnostics\TextFileListener.cs" />
80 <Compile Include="Diagnostics\TextFileListener.cs" />
81 <Compile Include="Diagnostics\Trace.cs" />
81 <Compile Include="Diagnostics\Trace.cs" />
82 <Compile Include="Diagnostics\TraceLog.cs" />
82 <Compile Include="Diagnostics\TraceLog.cs" />
83 <Compile Include="Diagnostics\TraceEvent.cs" />
83 <Compile Include="Diagnostics\TraceEvent.cs" />
84 <Compile Include="Diagnostics\TraceEventType.cs" />
84 <Compile Include="Diagnostics\TraceEventType.cs" />
85 <Compile Include="Diagnostics\TraceSourceAttribute.cs" />
85 <Compile Include="Diagnostics\TraceSourceAttribute.cs" />
86 <Compile Include="Formats\CharMap.cs" />
87 <Compile Include="Formats\InputScanner.cs" />
88 <Compile Include="Formats\Json\JsonStringScanner.cs" />
89 <Compile Include="Formats\Json\JsonTextScanner.cs" />
86 <Compile Include="ICancellable.cs" />
90 <Compile Include="ICancellable.cs" />
87 <Compile Include="IProgressHandler.cs" />
91 <Compile Include="IProgressHandler.cs" />
88 <Compile Include="IProgressNotifier.cs" />
92 <Compile Include="IProgressNotifier.cs" />
89 <Compile Include="IPromiseT.cs" />
93 <Compile Include="IPromiseT.cs" />
90 <Compile Include="IPromise.cs" />
94 <Compile Include="IPromise.cs" />
91 <Compile Include="IServiceLocator.cs" />
95 <Compile Include="IServiceLocator.cs" />
92 <Compile Include="ITaskController.cs" />
96 <Compile Include="ITaskController.cs" />
93 <Compile Include="Parallels\DispatchPool.cs" />
97 <Compile Include="Parallels\DispatchPool.cs" />
94 <Compile Include="Parallels\ArrayTraits.cs" />
98 <Compile Include="Parallels\ArrayTraits.cs" />
95 <Compile Include="Parallels\MTQueue.cs" />
99 <Compile Include="Parallels\MTQueue.cs" />
96 <Compile Include="Parallels\WorkerPool.cs" />
100 <Compile Include="Parallels\WorkerPool.cs" />
97 <Compile Include="ProgressInitEventArgs.cs" />
101 <Compile Include="ProgressInitEventArgs.cs" />
98 <Compile Include="Properties\AssemblyInfo.cs" />
102 <Compile Include="Properties\AssemblyInfo.cs" />
99 <Compile Include="Parallels\AsyncPool.cs" />
103 <Compile Include="Parallels\AsyncPool.cs" />
100 <Compile Include="Safe.cs" />
104 <Compile Include="Safe.cs" />
101 <Compile Include="SyncContextPromise.cs" />
105 <Compile Include="SyncContextPromise.cs" />
102 <Compile Include="ValueEventArgs.cs" />
106 <Compile Include="ValueEventArgs.cs" />
103 <Compile Include="PromiseExtensions.cs" />
107 <Compile Include="PromiseExtensions.cs" />
104 <Compile Include="SyncContextPromiseT.cs" />
108 <Compile Include="SyncContextPromiseT.cs" />
105 <Compile Include="Diagnostics\OperationContext.cs" />
109 <Compile Include="Diagnostics\OperationContext.cs" />
106 <Compile Include="Diagnostics\TraceContext.cs" />
110 <Compile Include="Diagnostics\TraceContext.cs" />
107 <Compile Include="Diagnostics\LogEventArgs.cs" />
111 <Compile Include="Diagnostics\LogEventArgs.cs" />
108 <Compile Include="Diagnostics\LogEventArgsT.cs" />
112 <Compile Include="Diagnostics\LogEventArgsT.cs" />
109 <Compile Include="Diagnostics\Extensions.cs" />
113 <Compile Include="Diagnostics\Extensions.cs" />
110 <Compile Include="PromiseEventType.cs" />
114 <Compile Include="PromiseEventType.cs" />
111 <Compile Include="Parallels\AsyncQueue.cs" />
115 <Compile Include="Parallels\AsyncQueue.cs" />
112 <Compile Include="PromiseT.cs" />
116 <Compile Include="PromiseT.cs" />
113 <Compile Include="IDeferred.cs" />
117 <Compile Include="IDeferred.cs" />
114 <Compile Include="IDeferredT.cs" />
118 <Compile Include="IDeferredT.cs" />
115 <Compile Include="Promise.cs" />
119 <Compile Include="Promise.cs" />
116 <Compile Include="PromiseTransientException.cs" />
120 <Compile Include="PromiseTransientException.cs" />
117 <Compile Include="Parallels\Signal.cs" />
121 <Compile Include="Parallels\Signal.cs" />
118 <Compile Include="Parallels\SharedLock.cs" />
122 <Compile Include="Parallels\SharedLock.cs" />
119 <Compile Include="Diagnostics\ILogWriter.cs" />
123 <Compile Include="Diagnostics\ILogWriter.cs" />
120 <Compile Include="Diagnostics\ListenerBase.cs" />
124 <Compile Include="Diagnostics\ListenerBase.cs" />
121 <Compile Include="Parallels\BlockingQueue.cs" />
125 <Compile Include="Parallels\BlockingQueue.cs" />
122 <Compile Include="AbstractEvent.cs" />
126 <Compile Include="AbstractEvent.cs" />
123 <Compile Include="AbstractPromise.cs" />
127 <Compile Include="AbstractPromise.cs" />
124 <Compile Include="AbstractPromiseT.cs" />
128 <Compile Include="AbstractPromiseT.cs" />
125 <Compile Include="FuncTask.cs" />
129 <Compile Include="FuncTask.cs" />
126 <Compile Include="FuncTaskBase.cs" />
130 <Compile Include="FuncTaskBase.cs" />
127 <Compile Include="FuncTaskT.cs" />
131 <Compile Include="FuncTaskT.cs" />
128 <Compile Include="ActionChainTaskBase.cs" />
132 <Compile Include="ActionChainTaskBase.cs" />
129 <Compile Include="ActionChainTask.cs" />
133 <Compile Include="ActionChainTask.cs" />
130 <Compile Include="ActionChainTaskT.cs" />
134 <Compile Include="ActionChainTaskT.cs" />
131 <Compile Include="FuncChainTaskBase.cs" />
135 <Compile Include="FuncChainTaskBase.cs" />
132 <Compile Include="FuncChainTask.cs" />
136 <Compile Include="FuncChainTask.cs" />
133 <Compile Include="FuncChainTaskT.cs" />
137 <Compile Include="FuncChainTaskT.cs" />
134 <Compile Include="ActionTaskBase.cs" />
138 <Compile Include="ActionTaskBase.cs" />
135 <Compile Include="ActionTask.cs" />
139 <Compile Include="ActionTask.cs" />
136 <Compile Include="ActionTaskT.cs" />
140 <Compile Include="ActionTaskT.cs" />
137 <Compile Include="ICancellationToken.cs" />
141 <Compile Include="ICancellationToken.cs" />
138 <Compile Include="SuccessPromise.cs" />
142 <Compile Include="SuccessPromise.cs" />
139 <Compile Include="SuccessPromiseT.cs" />
143 <Compile Include="SuccessPromiseT.cs" />
140 <Compile Include="PromiseAwaiterT.cs" />
144 <Compile Include="PromiseAwaiterT.cs" />
141 <Compile Include="PromiseAwaiter.cs" />
145 <Compile Include="PromiseAwaiter.cs" />
142 <Compile Include="Components\ComponentContainer.cs" />
146 <Compile Include="Components\ComponentContainer.cs" />
143 <Compile Include="Components\Disposable.cs" />
147 <Compile Include="Components\Disposable.cs" />
144 <Compile Include="Components\DisposablePool.cs" />
148 <Compile Include="Components\DisposablePool.cs" />
145 <Compile Include="Components\ObjectPool.cs" />
149 <Compile Include="Components\ObjectPool.cs" />
146 <Compile Include="Components\ServiceLocator.cs" />
150 <Compile Include="Components\ServiceLocator.cs" />
147 <Compile Include="Components\IInitializable.cs" />
151 <Compile Include="Components\IInitializable.cs" />
148 <Compile Include="TaskController.cs" />
152 <Compile Include="TaskController.cs" />
149 <Compile Include="Components\App.cs" />
153 <Compile Include="Components\App.cs" />
150 <Compile Include="Components\IRunnable.cs" />
154 <Compile Include="Components\IRunnable.cs" />
151 <Compile Include="Components\ExecutionState.cs" />
155 <Compile Include="Components\ExecutionState.cs" />
152 <Compile Include="Components\RunnableComponent.cs" />
156 <Compile Include="Components\RunnableComponent.cs" />
153 <Compile Include="Components\IFactory.cs" />
157 <Compile Include="Components\IFactory.cs" />
154 <Compile Include="Automaton\IAlphabet.cs" />
158 <Compile Include="Automaton\IAlphabet.cs" />
155 <Compile Include="Automaton\ParserException.cs" />
159 <Compile Include="Automaton\ParserException.cs" />
156 <Compile Include="Automaton\IndexedAlphabetBase.cs" />
160 <Compile Include="Automaton\IndexedAlphabetBase.cs" />
157 <Compile Include="Automaton\IAlphabetBuilder.cs" />
161 <Compile Include="Automaton\IAlphabetBuilder.cs" />
158 <Compile Include="Automaton\RegularExpressions\AltToken.cs" />
162 <Compile Include="Automaton\RegularExpressions\AltToken.cs" />
159 <Compile Include="Automaton\RegularExpressions\BinaryToken.cs" />
163 <Compile Include="Automaton\RegularExpressions\BinaryToken.cs" />
160 <Compile Include="Automaton\RegularExpressions\CatToken.cs" />
164 <Compile Include="Automaton\RegularExpressions\CatToken.cs" />
161 <Compile Include="Automaton\RegularExpressions\StarToken.cs" />
165 <Compile Include="Automaton\RegularExpressions\StarToken.cs" />
162 <Compile Include="Automaton\RegularExpressions\SymbolToken.cs" />
166 <Compile Include="Automaton\RegularExpressions\SymbolToken.cs" />
163 <Compile Include="Automaton\RegularExpressions\EmptyToken.cs" />
167 <Compile Include="Automaton\RegularExpressions\EmptyToken.cs" />
164 <Compile Include="Automaton\RegularExpressions\Token.cs" />
168 <Compile Include="Automaton\RegularExpressions\Token.cs" />
165 <Compile Include="Automaton\RegularExpressions\IVisitor.cs" />
169 <Compile Include="Automaton\RegularExpressions\IVisitor.cs" />
166 <Compile Include="Automaton\AutomatonTransition.cs" />
170 <Compile Include="Automaton\AutomatonTransition.cs" />
167 <Compile Include="Formats\JSON\JSONElementContext.cs" />
171 <Compile Include="Formats\Json\JsonElementContext.cs" />
168 <Compile Include="Formats\JSON\JSONElementType.cs" />
172 <Compile Include="Formats\Json\JsonElementType.cs" />
169 <Compile Include="Formats\JSON\JSONGrammar.cs" />
173 <Compile Include="Formats\Json\JsonGrammar.cs" />
170 <Compile Include="Formats\JSON\JSONParser.cs" />
174 <Compile Include="Formats\Json\JsonParser.cs" />
171 <Compile Include="Formats\JSON\JSONScanner.cs" />
175 <Compile Include="Formats\Json\JsonScanner.cs" />
172 <Compile Include="Formats\JSON\JsonTokenType.cs" />
176 <Compile Include="Formats\Json\JsonTokenType.cs" />
173 <Compile Include="Formats\JSON\JSONWriter.cs" />
177 <Compile Include="Formats\Json\JsonWriter.cs" />
174 <Compile Include="Formats\JSON\JSONXmlReader.cs" />
178 <Compile Include="Formats\Json\StringTranslator.cs" />
175 <Compile Include="Formats\JSON\JSONXmlReaderOptions.cs" />
176 <Compile Include="Formats\JSON\StringTranslator.cs" />
177 <Compile Include="Automaton\MapAlphabet.cs" />
179 <Compile Include="Automaton\MapAlphabet.cs" />
178 <Compile Include="Formats\CharAlphabet.cs" />
180 <Compile Include="Formats\CharAlphabet.cs" />
179 <Compile Include="Formats\ByteAlphabet.cs" />
181 <Compile Include="Formats\ByteAlphabet.cs" />
180 <Compile Include="Automaton\IDFATable.cs" />
182 <Compile Include="Automaton\IDFATable.cs" />
181 <Compile Include="Automaton\IDFATableBuilder.cs" />
183 <Compile Include="Automaton\IDFATableBuilder.cs" />
182 <Compile Include="Automaton\DFATable.cs" />
184 <Compile Include="Automaton\DFATable.cs" />
183 <Compile Include="Automaton\RegularExpressions\RegularExpressionVisitor.cs" />
185 <Compile Include="Automaton\RegularExpressions\RegularExpressionVisitor.cs" />
184 <Compile Include="Automaton\RegularExpressions\ITaggedDFABuilder.cs" />
186 <Compile Include="Automaton\RegularExpressions\ITaggedDFABuilder.cs" />
185 <Compile Include="Formats\TextScanner.cs" />
186 <Compile Include="Formats\StringScanner.cs" />
187 <Compile Include="Formats\ReaderScanner.cs" />
188 <Compile Include="Formats\ScannerContext.cs" />
189 <Compile Include="Formats\Grammar.cs" />
187 <Compile Include="Formats\Grammar.cs" />
190 <Compile Include="Automaton\RegularExpressions\EndTokenT.cs" />
188 <Compile Include="Automaton\RegularExpressions\EndTokenT.cs" />
191 <Compile Include="Automaton\RegularExpressions\EndToken.cs" />
189 <Compile Include="Automaton\RegularExpressions\EndToken.cs" />
192 <Compile Include="Automaton\RegularExpressions\RegularExpressionVisitorT.cs" />
190 <Compile Include="Automaton\RegularExpressions\RegularExpressionVisitorT.cs" />
193 <Compile Include="Automaton\AutomatonConst.cs" />
191 <Compile Include="Automaton\AutomatonConst.cs" />
194 <Compile Include="Automaton\RegularExpressions\RegularDFA.cs" />
192 <Compile Include="Automaton\RegularExpressions\RegularDFA.cs" />
195 <Compile Include="Components\LazyAndWeak.cs" />
193 <Compile Include="Components\LazyAndWeak.cs" />
196 <Compile Include="AbstractTask.cs" />
194 <Compile Include="AbstractTask.cs" />
197 <Compile Include="AbstractTaskT.cs" />
195 <Compile Include="AbstractTaskT.cs" />
198 <Compile Include="FailedPromise.cs" />
196 <Compile Include="FailedPromise.cs" />
199 <Compile Include="FailedPromiseT.cs" />
197 <Compile Include="FailedPromiseT.cs" />
200 <Compile Include="Components\PollingComponent.cs" />
198 <Compile Include="Components\PollingComponent.cs" />
201 <Compile Include="Xml\JsonXmlReader.cs" />
199 <Compile Include="Xml\JsonXmlReader.cs" />
202 <Compile Include="Xml\JsonXmlReaderOptions.cs" />
200 <Compile Include="Xml\JsonXmlReaderOptions.cs" />
203 <Compile Include="Xml\JsonXmlReaderPosition.cs" />
201 <Compile Include="Xml\JsonXmlReaderPosition.cs" />
204 <Compile Include="Xml\XmlSimpleAttribute.cs" />
202 <Compile Include="Xml\XmlSimpleAttribute.cs" />
205 <Compile Include="Xml\XmlNameContext.cs" />
203 <Compile Include="Xml\XmlNameContext.cs" />
206 </ItemGroup>
204 </ItemGroup>
207 <Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
205 <Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
208 <ItemGroup />
206 <ItemGroup />
209 <ProjectExtensions>
207 <ProjectExtensions>
210 <MonoDevelop>
208 <MonoDevelop>
211 <Properties>
209 <Properties>
212 <Policies>
210 <Policies>
213 <CSharpFormattingPolicy IndentBlock="True" IndentBraces="False" IndentSwitchSection="False" IndentSwitchCaseSection="True" LabelPositioning="OneLess" NewLinesForBracesInProperties="False" NewLinesForBracesInAccessors="False" NewLinesForBracesInAnonymousMethods="False" NewLinesForBracesInControlBlocks="False" NewLinesForBracesInAnonymousTypes="False" NewLinesForBracesInObjectCollectionArrayInitializers="False" NewLinesForBracesInLambdaExpressionBody="False" NewLineForElse="False" NewLineForCatch="False" NewLineForFinally="False" NewLineForMembersInObjectInit="False" NewLineForMembersInAnonymousTypes="False" NewLineForClausesInQuery="False" SpaceWithinMethodDeclarationParenthesis="False" SpaceBetweenEmptyMethodDeclarationParentheses="False" SpaceWithinMethodCallParentheses="False" SpaceBetweenEmptyMethodCallParentheses="False" SpaceAfterControlFlowStatementKeyword="True" SpaceWithinExpressionParentheses="False" SpaceWithinCastParentheses="False" SpaceWithinOtherParentheses="False" SpaceAfterCast="False" SpacesIgnoreAroundVariableDeclaration="False" SpaceBetweenEmptySquareBrackets="False" SpaceWithinSquareBrackets="False" SpaceAfterColonInBaseTypeDeclaration="True" SpaceAfterComma="True" SpaceAfterDot="False" SpaceAfterSemicolonsInForStatement="True" SpaceBeforeComma="False" SpaceBeforeDot="False" SpaceBeforeSemicolonsInForStatement="False" SpacingAroundBinaryOperator="Single" WrappingPreserveSingleLine="True" WrappingKeepStatementsOnSingleLine="True" PlaceSystemDirectiveFirst="True" NewLinesForBracesInTypes="True" NewLinesForBracesInMethods="True" SpacingAfterMethodDeclarationName="True" SpaceAfterMethodCallName="True" SpaceBeforeOpenSquareBracket="True" SpaceBeforeColonInBaseTypeDeclaration="True" scope="text/x-csharp" />
211 <CSharpFormattingPolicy IndentBlock="True" IndentBraces="False" IndentSwitchSection="False" IndentSwitchCaseSection="True" LabelPositioning="OneLess" NewLinesForBracesInProperties="False" NewLinesForBracesInAccessors="False" NewLinesForBracesInAnonymousMethods="False" NewLinesForBracesInControlBlocks="False" NewLinesForBracesInAnonymousTypes="False" NewLinesForBracesInObjectCollectionArrayInitializers="False" NewLinesForBracesInLambdaExpressionBody="False" NewLineForElse="False" NewLineForCatch="False" NewLineForFinally="False" NewLineForMembersInObjectInit="False" NewLineForMembersInAnonymousTypes="False" NewLineForClausesInQuery="False" SpaceWithinMethodDeclarationParenthesis="False" SpaceBetweenEmptyMethodDeclarationParentheses="False" SpaceWithinMethodCallParentheses="False" SpaceBetweenEmptyMethodCallParentheses="False" SpaceAfterControlFlowStatementKeyword="True" SpaceWithinExpressionParentheses="False" SpaceWithinCastParentheses="False" SpaceWithinOtherParentheses="False" SpaceAfterCast="False" SpacesIgnoreAroundVariableDeclaration="False" SpaceBetweenEmptySquareBrackets="False" SpaceWithinSquareBrackets="False" SpaceAfterColonInBaseTypeDeclaration="True" SpaceAfterComma="True" SpaceAfterDot="False" SpaceAfterSemicolonsInForStatement="True" SpaceBeforeComma="False" SpaceBeforeDot="False" SpaceBeforeSemicolonsInForStatement="False" SpacingAroundBinaryOperator="Single" WrappingPreserveSingleLine="True" WrappingKeepStatementsOnSingleLine="True" PlaceSystemDirectiveFirst="True" NewLinesForBracesInTypes="True" NewLinesForBracesInMethods="True" SpacingAfterMethodDeclarationName="True" SpaceAfterMethodCallName="True" SpaceBeforeOpenSquareBracket="True" SpaceBeforeColonInBaseTypeDeclaration="True" scope="text/x-csharp" />
214 <TextStylePolicy FileWidth="120" TabWidth="4" IndentWidth="4" RemoveTrailingWhitespace="True" NoTabsAfterNonTabs="False" TabsToSpaces="True" EolMarker="Unix" scope="text/x-csharp" />
212 <TextStylePolicy FileWidth="120" TabWidth="4" IndentWidth="4" RemoveTrailingWhitespace="True" NoTabsAfterNonTabs="False" TabsToSpaces="True" EolMarker="Unix" scope="text/x-csharp" />
215 <DotNetNamingPolicy DirectoryNamespaceAssociation="PrefixedHierarchical" ResourceNamePolicy="MSBuild" />
213 <DotNetNamingPolicy DirectoryNamespaceAssociation="PrefixedHierarchical" ResourceNamePolicy="MSBuild" />
216 <TextStylePolicy FileWidth="120" TabWidth="4" TabsToSpaces="False" IndentWidth="4" RemoveTrailingWhitespace="True" NoTabsAfterNonTabs="False" EolMarker="Native" scope="application/xml" />
214 <TextStylePolicy FileWidth="120" TabWidth="4" TabsToSpaces="False" IndentWidth="4" RemoveTrailingWhitespace="True" NoTabsAfterNonTabs="False" EolMarker="Native" scope="application/xml" />
217 <XmlFormattingPolicy scope="application/xml">
215 <XmlFormattingPolicy scope="application/xml">
218 <DefaultFormat OmitXmlDeclaration="False" NewLineChars="&#xA;" IndentContent="True" ContentIndentString=" " AttributesInNewLine="False" MaxAttributesPerLine="10" AttributesIndentString=" " WrapAttributes="False" AlignAttributes="False" AlignAttributeValues="False" QuoteChar="&quot;" SpacesBeforeAssignment="0" SpacesAfterAssignment="0" EmptyLinesBeforeStart="0" EmptyLinesAfterStart="0" EmptyLinesBeforeEnd="0" EmptyLinesAfterEnd="0" />
216 <DefaultFormat OmitXmlDeclaration="False" NewLineChars="&#xA;" IndentContent="True" ContentIndentString=" " AttributesInNewLine="False" MaxAttributesPerLine="10" AttributesIndentString=" " WrapAttributes="False" AlignAttributes="False" AlignAttributeValues="False" QuoteChar="&quot;" SpacesBeforeAssignment="0" SpacesAfterAssignment="0" EmptyLinesBeforeStart="0" EmptyLinesAfterStart="0" EmptyLinesBeforeEnd="0" EmptyLinesAfterEnd="0" />
219 </XmlFormattingPolicy>
217 </XmlFormattingPolicy>
220 <TextStylePolicy FileWidth="120" TabWidth="4" TabsToSpaces="False" IndentWidth="4" RemoveTrailingWhitespace="True" NoTabsAfterNonTabs="False" EolMarker="Native" scope="text/plain" />
218 <TextStylePolicy FileWidth="120" TabWidth="4" TabsToSpaces="False" IndentWidth="4" RemoveTrailingWhitespace="True" NoTabsAfterNonTabs="False" EolMarker="Native" scope="text/plain" />
221 <NameConventionPolicy>
219 <NameConventionPolicy>
222 <Rules>
220 <Rules>
223 <NamingRule Name="Namespaces" AffectedEntity="Namespace" VisibilityMask="VisibilityMask" NamingStyle="PascalCase" IncludeInstanceMembers="True" IncludeStaticEntities="True" />
221 <NamingRule Name="Namespaces" AffectedEntity="Namespace" VisibilityMask="VisibilityMask" NamingStyle="PascalCase" IncludeInstanceMembers="True" IncludeStaticEntities="True" />
224 <NamingRule Name="Types" AffectedEntity="Class, Struct, Enum, Delegate" VisibilityMask="VisibilityMask" NamingStyle="PascalCase" IncludeInstanceMembers="True" IncludeStaticEntities="True" />
222 <NamingRule Name="Types" AffectedEntity="Class, Struct, Enum, Delegate" VisibilityMask="VisibilityMask" NamingStyle="PascalCase" IncludeInstanceMembers="True" IncludeStaticEntities="True" />
225 <NamingRule Name="Interfaces" AffectedEntity="Interface" VisibilityMask="VisibilityMask" NamingStyle="PascalCase" IncludeInstanceMembers="True" IncludeStaticEntities="True">
223 <NamingRule Name="Interfaces" AffectedEntity="Interface" VisibilityMask="VisibilityMask" NamingStyle="PascalCase" IncludeInstanceMembers="True" IncludeStaticEntities="True">
226 <RequiredPrefixes>
224 <RequiredPrefixes>
227 <String>I</String>
225 <String>I</String>
228 </RequiredPrefixes>
226 </RequiredPrefixes>
229 </NamingRule>
227 </NamingRule>
230 <NamingRule Name="Attributes" AffectedEntity="CustomAttributes" VisibilityMask="VisibilityMask" NamingStyle="PascalCase" IncludeInstanceMembers="True" IncludeStaticEntities="True">
228 <NamingRule Name="Attributes" AffectedEntity="CustomAttributes" VisibilityMask="VisibilityMask" NamingStyle="PascalCase" IncludeInstanceMembers="True" IncludeStaticEntities="True">
231 <RequiredSuffixes>
229 <RequiredSuffixes>
232 <String>Attribute</String>
230 <String>Attribute</String>
233 </RequiredSuffixes>
231 </RequiredSuffixes>
234 </NamingRule>
232 </NamingRule>
235 <NamingRule Name="Event Arguments" AffectedEntity="CustomEventArgs" VisibilityMask="VisibilityMask" NamingStyle="PascalCase" IncludeInstanceMembers="True" IncludeStaticEntities="True">
233 <NamingRule Name="Event Arguments" AffectedEntity="CustomEventArgs" VisibilityMask="VisibilityMask" NamingStyle="PascalCase" IncludeInstanceMembers="True" IncludeStaticEntities="True">
236 <RequiredSuffixes>
234 <RequiredSuffixes>
237 <String>EventArgs</String>
235 <String>EventArgs</String>
238 </RequiredSuffixes>
236 </RequiredSuffixes>
239 </NamingRule>
237 </NamingRule>
240 <NamingRule Name="Exceptions" AffectedEntity="CustomExceptions" VisibilityMask="VisibilityMask" NamingStyle="PascalCase" IncludeInstanceMembers="True" IncludeStaticEntities="True">
238 <NamingRule Name="Exceptions" AffectedEntity="CustomExceptions" VisibilityMask="VisibilityMask" NamingStyle="PascalCase" IncludeInstanceMembers="True" IncludeStaticEntities="True">
241 <RequiredSuffixes>
239 <RequiredSuffixes>
242 <String>Exception</String>
240 <String>Exception</String>
243 </RequiredSuffixes>
241 </RequiredSuffixes>
244 </NamingRule>
242 </NamingRule>
245 <NamingRule Name="Methods" AffectedEntity="Methods" VisibilityMask="VisibilityMask" NamingStyle="PascalCase" IncludeInstanceMembers="True" IncludeStaticEntities="True" />
243 <NamingRule Name="Methods" AffectedEntity="Methods" VisibilityMask="VisibilityMask" NamingStyle="PascalCase" IncludeInstanceMembers="True" IncludeStaticEntities="True" />
246 <NamingRule Name="Static Readonly Fields" AffectedEntity="ReadonlyField" VisibilityMask="Internal, Protected, Public" NamingStyle="CamelCase" IncludeInstanceMembers="False" IncludeStaticEntities="True" />
244 <NamingRule Name="Static Readonly Fields" AffectedEntity="ReadonlyField" VisibilityMask="Internal, Protected, Public" NamingStyle="CamelCase" IncludeInstanceMembers="False" IncludeStaticEntities="True" />
247 <NamingRule Name="Fields (Non Private)" AffectedEntity="Field" VisibilityMask="Internal, Public" NamingStyle="CamelCase" IncludeInstanceMembers="True" IncludeStaticEntities="True" />
245 <NamingRule Name="Fields (Non Private)" AffectedEntity="Field" VisibilityMask="Internal, Public" NamingStyle="CamelCase" IncludeInstanceMembers="True" IncludeStaticEntities="True" />
248 <NamingRule Name="ReadOnly Fields (Non Private)" AffectedEntity="ReadonlyField" VisibilityMask="Internal, Public" NamingStyle="CamelCase" IncludeInstanceMembers="True" IncludeStaticEntities="False" />
246 <NamingRule Name="ReadOnly Fields (Non Private)" AffectedEntity="ReadonlyField" VisibilityMask="Internal, Public" NamingStyle="CamelCase" IncludeInstanceMembers="True" IncludeStaticEntities="False" />
249 <NamingRule Name="Fields (Private)" AffectedEntity="Field, ReadonlyField" VisibilityMask="Private, Protected" NamingStyle="CamelCase" IncludeInstanceMembers="True" IncludeStaticEntities="False">
247 <NamingRule Name="Fields (Private)" AffectedEntity="Field, ReadonlyField" VisibilityMask="Private, Protected" NamingStyle="CamelCase" IncludeInstanceMembers="True" IncludeStaticEntities="False">
250 <RequiredPrefixes>
248 <RequiredPrefixes>
251 <String>m_</String>
249 <String>m_</String>
252 </RequiredPrefixes>
250 </RequiredPrefixes>
253 </NamingRule>
251 </NamingRule>
254 <NamingRule Name="Static Fields (Private)" AffectedEntity="Field" VisibilityMask="Private" NamingStyle="CamelCase" IncludeInstanceMembers="False" IncludeStaticEntities="True">
252 <NamingRule Name="Static Fields (Private)" AffectedEntity="Field" VisibilityMask="Private" NamingStyle="CamelCase" IncludeInstanceMembers="False" IncludeStaticEntities="True">
255 <RequiredPrefixes>
253 <RequiredPrefixes>
256 <String>_</String>
254 <String>_</String>
257 </RequiredPrefixes>
255 </RequiredPrefixes>
258 </NamingRule>
256 </NamingRule>
259 <NamingRule Name="ReadOnly Fields (Private)" AffectedEntity="ReadonlyField" VisibilityMask="Private, Protected" NamingStyle="CamelCase" IncludeInstanceMembers="True" IncludeStaticEntities="False">
257 <NamingRule Name="ReadOnly Fields (Private)" AffectedEntity="ReadonlyField" VisibilityMask="Private, Protected" NamingStyle="CamelCase" IncludeInstanceMembers="True" IncludeStaticEntities="False">
260 <RequiredPrefixes>
258 <RequiredPrefixes>
261 <String>m_</String>
259 <String>m_</String>
262 </RequiredPrefixes>
260 </RequiredPrefixes>
263 </NamingRule>
261 </NamingRule>
264 <NamingRule Name="Constant Fields" AffectedEntity="ConstantField" VisibilityMask="VisibilityMask" NamingStyle="AllUpper" IncludeInstanceMembers="True" IncludeStaticEntities="True" />
262 <NamingRule Name="Constant Fields" AffectedEntity="ConstantField" VisibilityMask="VisibilityMask" NamingStyle="AllUpper" IncludeInstanceMembers="True" IncludeStaticEntities="True" />
265 <NamingRule Name="Properties" AffectedEntity="Property" VisibilityMask="VisibilityMask" NamingStyle="PascalCase" IncludeInstanceMembers="True" IncludeStaticEntities="True" />
263 <NamingRule Name="Properties" AffectedEntity="Property" VisibilityMask="VisibilityMask" NamingStyle="PascalCase" IncludeInstanceMembers="True" IncludeStaticEntities="True" />
266 <NamingRule Name="Events" AffectedEntity="Event" VisibilityMask="VisibilityMask" NamingStyle="PascalCase" IncludeInstanceMembers="True" IncludeStaticEntities="True" />
264 <NamingRule Name="Events" AffectedEntity="Event" VisibilityMask="VisibilityMask" NamingStyle="PascalCase" IncludeInstanceMembers="True" IncludeStaticEntities="True" />
267 <NamingRule Name="Enum Members" AffectedEntity="EnumMember" VisibilityMask="VisibilityMask" NamingStyle="PascalCase" IncludeInstanceMembers="True" IncludeStaticEntities="True" />
265 <NamingRule Name="Enum Members" AffectedEntity="EnumMember" VisibilityMask="VisibilityMask" NamingStyle="PascalCase" IncludeInstanceMembers="True" IncludeStaticEntities="True" />
268 <NamingRule Name="Parameters" AffectedEntity="Parameter, LocalVariable" VisibilityMask="VisibilityMask" NamingStyle="CamelCase" IncludeInstanceMembers="True" IncludeStaticEntities="True" />
266 <NamingRule Name="Parameters" AffectedEntity="Parameter, LocalVariable" VisibilityMask="VisibilityMask" NamingStyle="CamelCase" IncludeInstanceMembers="True" IncludeStaticEntities="True" />
269 <NamingRule Name="Type Parameters" AffectedEntity="TypeParameter" VisibilityMask="VisibilityMask" NamingStyle="PascalCase" IncludeInstanceMembers="True" IncludeStaticEntities="True">
267 <NamingRule Name="Type Parameters" AffectedEntity="TypeParameter" VisibilityMask="VisibilityMask" NamingStyle="PascalCase" IncludeInstanceMembers="True" IncludeStaticEntities="True">
270 <RequiredPrefixes>
268 <RequiredPrefixes>
271 <String>T</String>
269 <String>T</String>
272 </RequiredPrefixes>
270 </RequiredPrefixes>
273 </NamingRule>
271 </NamingRule>
274 </Rules>
272 </Rules>
275 </NameConventionPolicy>
273 </NameConventionPolicy>
276 </Policies>
274 </Policies>
277 </Properties>
275 </Properties>
278 </MonoDevelop>
276 </MonoDevelop>
279 </ProjectExtensions>
277 </ProjectExtensions>
280 <ItemGroup />
278 <ItemGroup />
281 </Project> No newline at end of file
279 </Project>
@@ -1,152 +1,166
1 using System;
1 using System;
2 using System.Collections.Generic;
2 using System.Collections.Generic;
3 using System.Linq;
3 using System.Linq;
4 using System.Text;
4 using System.Text;
5 using System.Text.RegularExpressions;
5 using System.Text.RegularExpressions;
6 using System.Diagnostics;
6 using System.Diagnostics;
7 using System.Collections;
7 using System.Collections;
8 using System.Runtime.CompilerServices;
8
9
9 #if NET_4_5
10 #if NET_4_5
10 using System.Threading.Tasks;
11 using System.Threading.Tasks;
11 #endif
12 #endif
12
13
13 namespace Implab
14 namespace Implab
14 {
15 {
15 public static class Safe
16 public static class Safe
16 {
17 {
18 [MethodImpl(MethodImplOptions.AggressiveInlining)]
17 public static void ArgumentAssert(bool condition, string paramName) {
19 public static void ArgumentAssert(bool condition, string paramName) {
18 if (!condition)
20 if (!condition)
19 throw new ArgumentException("The parameter is invalid", paramName);
21 throw new ArgumentException("The parameter is invalid", paramName);
20 }
22 }
21
23
24 [MethodImpl(MethodImplOptions.AggressiveInlining)]
22 public static void ArgumentMatch(string value, string paramName, Regex rx) {
25 public static void ArgumentMatch(string value, string paramName, Regex rx) {
23 if (rx == null)
26 if (rx == null)
24 throw new ArgumentNullException("rx");
27 throw new ArgumentNullException("rx");
25 if (!rx.IsMatch(value))
28 if (!rx.IsMatch(value))
26 throw new ArgumentException(String.Format("The prameter value must match {0}", rx), paramName);
29 throw new ArgumentException(String.Format("The prameter value must match {0}", rx), paramName);
27 }
30 }
28
31
32 [MethodImpl(MethodImplOptions.AggressiveInlining)]
29 public static void ArgumentNotEmpty(string value, string paramName) {
33 public static void ArgumentNotEmpty(string value, string paramName) {
30 if (String.IsNullOrEmpty(value))
34 if (String.IsNullOrEmpty(value))
31 throw new ArgumentException("The parameter can't be empty", paramName);
35 throw new ArgumentException("The parameter can't be empty", paramName);
32 }
36 }
33
37
38 [MethodImpl(MethodImplOptions.AggressiveInlining)]
34 public static void ArgumentNotEmpty<T>(T[] value, string paramName) {
39 public static void ArgumentNotEmpty<T>(T[] value, string paramName) {
35 if (value == null || value.Length == 0)
40 if (value == null || value.Length == 0)
36 throw new ArgumentException("The array must be not emty", paramName);
41 throw new ArgumentException("The array must be not emty", paramName);
37 }
42 }
38
43
44 [MethodImpl(MethodImplOptions.AggressiveInlining)]
39 public static void ArgumentNotNull(object value, string paramName) {
45 public static void ArgumentNotNull(object value, string paramName) {
40 if (value == null)
46 if (value == null)
41 throw new ArgumentNullException(paramName);
47 throw new ArgumentNullException(paramName);
42 }
48 }
43
49
50 [MethodImpl(MethodImplOptions.AggressiveInlining)]
51 internal static void ArgumentGreaterThan(int value, int min, string paramName) {
52 if (value < min)
53 throw new ArgumentOutOfRangeException(paramName);
54 }
55
56 [MethodImpl(MethodImplOptions.AggressiveInlining)]
44 public static void ArgumentInRange(int value, int min, int max, string paramName) {
57 public static void ArgumentInRange(int value, int min, int max, string paramName) {
45 if (value < min || value > max)
58 if (value < min || value > max)
46 throw new ArgumentOutOfRangeException(paramName);
59 throw new ArgumentOutOfRangeException(paramName);
47 }
60 }
48
61
62 [MethodImpl(MethodImplOptions.AggressiveInlining)]
49 public static void ArgumentOfType(object value, Type type, string paramName) {
63 public static void ArgumentOfType(object value, Type type, string paramName) {
50 if (!type.IsInstanceOfType(value))
64 if (!type.IsInstanceOfType(value))
51 throw new ArgumentException(String.Format("The parameter must be of type {0}", type), paramName);
65 throw new ArgumentException(String.Format("The parameter must be of type {0}", type), paramName);
52 }
66 }
53
67
54 public static void Dispose(params IDisposable[] objects) {
68 public static void Dispose(params IDisposable[] objects) {
55 foreach (var d in objects)
69 foreach (var d in objects)
56 if (d != null)
70 if (d != null)
57 d.Dispose();
71 d.Dispose();
58 }
72 }
59
73
60 public static void Dispose(params object[] objects) {
74 public static void Dispose(params object[] objects) {
61 foreach (var obj in objects) {
75 foreach (var obj in objects) {
62 var d = obj as IDisposable;
76 var d = obj as IDisposable;
63 if (d != null)
77 if (d != null)
64 d.Dispose();
78 d.Dispose();
65 }
79 }
66 }
80 }
67
81
68 public static void DisposeCollection(IEnumerable<IDisposable> objects) {
82 public static void DisposeCollection(IEnumerable<IDisposable> objects) {
69 foreach (var d in objects)
83 foreach (var d in objects)
70 Dispose(d);
84 Dispose(d);
71 }
85 }
72
86
73 public static void DisposeCollection(IEnumerable objects) {
87 public static void DisposeCollection(IEnumerable objects) {
74 foreach (var d in objects)
88 foreach (var d in objects)
75 Dispose(d);
89 Dispose(d);
76 }
90 }
77
91
78 public static void Dispose(object obj) {
92 public static void Dispose(object obj) {
79 if (obj is IDisposable) {
93 if (obj is IDisposable) {
80 Dispose((IDisposable)obj);
94 Dispose((IDisposable)obj);
81 } else if (obj is IEnumerable) {
95 } else if (obj is IEnumerable) {
82 DisposeCollection((IEnumerable)obj);
96 DisposeCollection((IEnumerable)obj);
83 }
97 }
84 }
98 }
85
99
86 [DebuggerStepThrough]
100 [DebuggerStepThrough]
87 public static void DispatchEvent<T>(this EventHandler<T> handler, object sender, T args) {
101 public static void DispatchEvent<T>(this EventHandler<T> handler, object sender, T args) {
88 if (handler != null)
102 if (handler != null)
89 handler(sender, args);
103 handler(sender, args);
90 }
104 }
91
105
92 [DebuggerStepThrough]
106 [DebuggerStepThrough]
93 public static void DispatchEvent(this EventHandler handler, object sender, EventArgs args) {
107 public static void DispatchEvent(this EventHandler handler, object sender, EventArgs args) {
94 if (handler != null)
108 if (handler != null)
95 handler(sender, args);
109 handler(sender, args);
96 }
110 }
97
111
98 [DebuggerStepThrough]
112 [DebuggerStepThrough]
99 public static IPromise<T> Run<T>(Func<T> action) {
113 public static IPromise<T> Run<T>(Func<T> action) {
100 ArgumentNotNull(action, "action");
114 ArgumentNotNull(action, "action");
101
115
102 try {
116 try {
103 return Promise<T>.FromResult(action());
117 return Promise<T>.FromResult(action());
104 } catch (Exception err) {
118 } catch (Exception err) {
105 return Promise<T>.FromException(err);
119 return Promise<T>.FromException(err);
106 }
120 }
107 }
121 }
108
122
109 [DebuggerStepThrough]
123 [DebuggerStepThrough]
110 public static IPromise Run(Action action) {
124 public static IPromise Run(Action action) {
111 ArgumentNotNull(action, "action");
125 ArgumentNotNull(action, "action");
112
126
113 try {
127 try {
114 action();
128 action();
115 return Promise.Success;
129 return Promise.Success;
116 } catch (Exception err) {
130 } catch (Exception err) {
117 return new FailedPromise(err);
131 return new FailedPromise(err);
118 }
132 }
119 }
133 }
120
134
121 [DebuggerStepThrough]
135 [DebuggerStepThrough]
122 public static IPromise Run(Func<IPromise> action) {
136 public static IPromise Run(Func<IPromise> action) {
123 ArgumentNotNull(action, "action");
137 ArgumentNotNull(action, "action");
124
138
125 try {
139 try {
126 return action() ?? new FailedPromise(new Exception("The action returned null"));
140 return action() ?? new FailedPromise(new Exception("The action returned null"));
127 } catch (Exception err) {
141 } catch (Exception err) {
128 return new FailedPromise(err);
142 return new FailedPromise(err);
129 }
143 }
130 }
144 }
131
145
132 public static void NoWait(IPromise promise) {
146 public static void NoWait(IPromise promise) {
133 }
147 }
134
148
135 [DebuggerStepThrough]
149 [DebuggerStepThrough]
136 public static IPromise<T> Run<T>(Func<IPromise<T>> action) {
150 public static IPromise<T> Run<T>(Func<IPromise<T>> action) {
137 ArgumentNotNull(action, "action");
151 ArgumentNotNull(action, "action");
138
152
139 try {
153 try {
140 return action() ?? Promise<T>.FromException(new Exception("The action returned null"));
154 return action() ?? Promise<T>.FromException(new Exception("The action returned null"));
141 } catch (Exception err) {
155 } catch (Exception err) {
142 return Promise<T>.FromException(err);
156 return Promise<T>.FromException(err);
143 }
157 }
144 }
158 }
145
159
146 #if NET_4_5
160 #if NET_4_5
147 public static void NoWait(Task t) {
161 public static void NoWait(Task t) {
148 }
162 }
149 #endif
163 #endif
150
164
151 }
165 }
152 }
166 }
@@ -1,629 +1,626
1 using Implab.Formats.JSON;
1 using Implab.Formats.Json;
2 using System;
2 using System;
3 using System.Collections.Generic;
3 using System.Collections.Generic;
4 using System.Globalization;
4 using System.Globalization;
5 using System.Linq;
5 using System.Linq;
6 using System.Text;
7 using System.Threading.Tasks;
8 using System.Xml;
6 using System.Xml;
9
7
10 namespace Implab.Xml {
8 namespace Implab.Xml {
11 public class JsonXmlReader : XmlReader {
9 public class JsonXmlReader : XmlReader {
12 struct JsonContext {
10 struct JsonContext {
13 public string localName;
11 public string localName;
14 public bool skip;
12 public bool skip;
15 }
13 }
16
14
17 JSONParser m_parser;
15 JsonParser m_parser;
18 JsonXmlReaderOptions m_options;
16 JsonXmlReaderOptions m_options;
19 JsonXmlReaderPosition m_position = JsonXmlReaderPosition.Initial;
17 JsonXmlReaderPosition m_position = JsonXmlReaderPosition.Initial;
20 XmlNameTable m_nameTable;
18 XmlNameTable m_nameTable;
21
19
22 readonly string m_jsonRootName;
20 readonly string m_jsonRootName;
23 readonly string m_jsonNamespace;
21 readonly string m_jsonNamespace;
24 readonly string m_jsonPrefix;
22 readonly string m_jsonPrefix;
25 readonly bool m_jsonFlattenArrays;
23 readonly bool m_jsonFlattenArrays;
26 readonly string m_jsonArrayItemName;
24 readonly string m_jsonArrayItemName;
27
25
28 string m_jsonLocalName;
26 string m_jsonLocalName;
29 string m_jsonValueName;
27 string m_jsonValueName;
30 bool m_jsonSkip; // indicates wheather to generate closing tag for objects or arrays
28 bool m_jsonSkip; // indicates wheather to generate closing tag for objects or arrays
31
29
32 readonly Stack<JsonContext> m_jsonNameStack = new Stack<JsonContext>();
30 readonly Stack<JsonContext> m_jsonNameStack = new Stack<JsonContext>();
33
31
34 XmlQualifiedName m_elementQName;
32 XmlQualifiedName m_elementQName;
35 string m_elementPrefix;
33 string m_elementPrefix;
36 int m_elementDepth;
34 int m_elementDepth;
37 bool m_elementIsEmpty;
35 bool m_elementIsEmpty;
38
36
39 XmlQualifiedName m_qName;
37 XmlQualifiedName m_qName;
40 string m_prefix;
38 string m_prefix;
41 int m_xmlDepth;
39 int m_xmlDepth;
42
40
43 XmlSimpleAttribute[] m_attributes;
41 XmlSimpleAttribute[] m_attributes;
44 object m_value;
42 object m_value;
45 bool m_isEmpty;
43 bool m_isEmpty;
46
44
47 XmlNodeType m_nodeType = XmlNodeType.None;
45 XmlNodeType m_nodeType = XmlNodeType.None;
48
46
49 bool m_isAttribute; // indicates that we are reading attribute nodes
47 bool m_isAttribute; // indicates that we are reading attribute nodes
50 int m_currentAttribute;
48 int m_currentAttribute;
51 bool m_currentAttributeRead;
49 bool m_currentAttributeRead;
52
50
53
51
54 XmlNameContext m_context;
52 XmlNameContext m_context;
55 int m_nextPrefix = 1;
56
53
57 readonly string m_xmlnsPrefix;
54 readonly string m_xmlnsPrefix;
58 readonly string m_xmlnsNamespace;
55 readonly string m_xmlnsNamespace;
59 readonly string m_xsiPrefix;
56 readonly string m_xsiPrefix;
60 readonly string m_xsiNamespace;
57 readonly string m_xsiNamespace;
61
58
62
59
63 public JsonXmlReader(JSONParser parser, JsonXmlReaderOptions options) {
60 public JsonXmlReader(JsonParser parser, JsonXmlReaderOptions options) {
64 Safe.ArgumentNotNull(parser, nameof(parser));
61 Safe.ArgumentNotNull(parser, nameof(parser));
65 m_parser = parser;
62 m_parser = parser;
66
63
67 m_options = options ?? new JsonXmlReaderOptions();
64 m_options = options ?? new JsonXmlReaderOptions();
68
65
69 m_jsonFlattenArrays = m_options.FlattenArrays;
66 m_jsonFlattenArrays = m_options.FlattenArrays;
70 m_nameTable = m_options.NameTable ?? new NameTable();
67 m_nameTable = m_options.NameTable ?? new NameTable();
71
68
72 m_jsonRootName = m_nameTable.Add(string.IsNullOrEmpty(m_options.RootName) ? "data" : m_options.RootName);
69 m_jsonRootName = m_nameTable.Add(string.IsNullOrEmpty(m_options.RootName) ? "data" : m_options.RootName);
73 m_jsonArrayItemName = m_nameTable.Add(string.IsNullOrEmpty(m_options.ArrayItemName) ? "item" : m_options.ArrayItemName);
70 m_jsonArrayItemName = m_nameTable.Add(string.IsNullOrEmpty(m_options.ArrayItemName) ? "item" : m_options.ArrayItemName);
74 m_jsonNamespace = m_nameTable.Add(m_options.NamespaceUri ?? string.Empty);
71 m_jsonNamespace = m_nameTable.Add(m_options.NamespaceUri ?? string.Empty);
75 m_jsonPrefix = m_nameTable.Add(m_options.NodesPrefix ?? string.Empty);
72 m_jsonPrefix = m_nameTable.Add(m_options.NodesPrefix ?? string.Empty);
76 m_xmlnsPrefix = m_nameTable.Add(XmlNameContext.XmlnsPrefix);
73 m_xmlnsPrefix = m_nameTable.Add(XmlNameContext.XmlnsPrefix);
77 m_xmlnsNamespace = m_nameTable.Add(XmlNameContext.XmlnsNamespace);
74 m_xmlnsNamespace = m_nameTable.Add(XmlNameContext.XmlnsNamespace);
78 m_xsiPrefix = m_nameTable.Add(XmlNameContext.XsiPrefix);
75 m_xsiPrefix = m_nameTable.Add(XmlNameContext.XsiPrefix);
79 m_xsiNamespace = m_nameTable.Add(XmlNameContext.XsiNamespace);
76 m_xsiNamespace = m_nameTable.Add(XmlNameContext.XsiNamespace);
80
77
81 // TODO validate m_jsonRootName, m_jsonArrayItemName
78 // TODO validate m_jsonRootName, m_jsonArrayItemName
82
79
83 m_context = new XmlNameContext(null);
80 m_context = new XmlNameContext(null);
84 }
81 }
85
82
86 public override int AttributeCount {
83 public override int AttributeCount {
87 get {
84 get {
88 return m_attributes == null ? 0 : m_attributes.Length;
85 return m_attributes == null ? 0 : m_attributes.Length;
89 }
86 }
90 }
87 }
91
88
92 public override string BaseURI {
89 public override string BaseURI {
93 get {
90 get {
94 return string.Empty;
91 return string.Empty;
95 }
92 }
96 }
93 }
97
94
98 public override int Depth {
95 public override int Depth {
99 get {
96 get {
100 return m_xmlDepth;
97 return m_xmlDepth;
101 }
98 }
102 }
99 }
103
100
104 public override bool EOF {
101 public override bool EOF {
105 get {
102 get {
106 return m_position == JsonXmlReaderPosition.Eof;
103 return m_position == JsonXmlReaderPosition.Eof;
107 }
104 }
108 }
105 }
109
106
110 public override bool IsEmptyElement {
107 public override bool IsEmptyElement {
111 get { return m_isEmpty; }
108 get { return m_isEmpty; }
112 }
109 }
113
110
114
111
115 public override string LocalName {
112 public override string LocalName {
116 get {
113 get {
117 return m_qName.Name;
114 return m_qName.Name;
118 }
115 }
119 }
116 }
120
117
121 public override string NamespaceURI {
118 public override string NamespaceURI {
122 get {
119 get {
123 return m_qName.Namespace;
120 return m_qName.Namespace;
124 }
121 }
125 }
122 }
126
123
127 public override XmlNameTable NameTable {
124 public override XmlNameTable NameTable {
128 get {
125 get {
129 return m_nameTable;
126 return m_nameTable;
130 }
127 }
131 }
128 }
132
129
133 public override XmlNodeType NodeType {
130 public override XmlNodeType NodeType {
134 get {
131 get {
135 return m_nodeType;
132 return m_nodeType;
136 }
133 }
137 }
134 }
138
135
139 public override string Prefix {
136 public override string Prefix {
140 get {
137 get {
141 return m_prefix;
138 return m_prefix;
142 }
139 }
143 }
140 }
144
141
145 public override ReadState ReadState {
142 public override ReadState ReadState {
146 get {
143 get {
147 switch (m_position) {
144 switch (m_position) {
148 case JsonXmlReaderPosition.Initial:
145 case JsonXmlReaderPosition.Initial:
149 return ReadState.Initial;
146 return ReadState.Initial;
150 case JsonXmlReaderPosition.Eof:
147 case JsonXmlReaderPosition.Eof:
151 return ReadState.EndOfFile;
148 return ReadState.EndOfFile;
152 case JsonXmlReaderPosition.Closed:
149 case JsonXmlReaderPosition.Closed:
153 return ReadState.Closed;
150 return ReadState.Closed;
154 case JsonXmlReaderPosition.Error:
151 case JsonXmlReaderPosition.Error:
155 return ReadState.Error;
152 return ReadState.Error;
156 default:
153 default:
157 return ReadState.Interactive;
154 return ReadState.Interactive;
158 };
155 };
159 }
156 }
160 }
157 }
161
158
162 public override string Value {
159 public override string Value {
163 get {
160 get {
164 return ConvertValueToString(m_value);
161 return ConvertValueToString(m_value);
165 }
162 }
166 }
163 }
167
164
168 static string ConvertValueToString(object value) {
165 static string ConvertValueToString(object value) {
169 if (value == null)
166 if (value == null)
170 return string.Empty;
167 return string.Empty;
171
168
172 switch (Convert.GetTypeCode(value)) {
169 switch (Convert.GetTypeCode(value)) {
173 case TypeCode.Double:
170 case TypeCode.Double:
174 return ((double)value).ToString(CultureInfo.InvariantCulture);
171 return ((double)value).ToString(CultureInfo.InvariantCulture);
175 case TypeCode.String:
172 case TypeCode.String:
176 return (string)value;
173 return (string)value;
177 case TypeCode.Boolean:
174 case TypeCode.Boolean:
178 return (bool)value ? "true" : "false";
175 return (bool)value ? "true" : "false";
179 default:
176 default:
180 return value.ToString();
177 return value.ToString();
181 }
178 }
182 }
179 }
183
180
184 public override string GetAttribute(int i) {
181 public override string GetAttribute(int i) {
185 Safe.ArgumentInRange(i, 0, AttributeCount - 1, nameof(i));
182 Safe.ArgumentInRange(i, 0, AttributeCount - 1, nameof(i));
186 return ConvertValueToString(m_attributes[i].Value);
183 return ConvertValueToString(m_attributes[i].Value);
187 }
184 }
188
185
189 public override string GetAttribute(string name) {
186 public override string GetAttribute(string name) {
190 if (m_attributes == null)
187 if (m_attributes == null)
191 return null;
188 return null;
192 var qName = m_context.Resolve(name);
189 var qName = m_context.Resolve(name);
193 var attr = Array.Find(m_attributes, x => x.QName == qName);
190 var attr = Array.Find(m_attributes, x => x.QName == qName);
194 var value = ConvertValueToString(attr?.Value);
191 var value = ConvertValueToString(attr?.Value);
195 return value == string.Empty ? null : value;
192 return value == string.Empty ? null : value;
196 }
193 }
197
194
198 public override string GetAttribute(string name, string namespaceURI) {
195 public override string GetAttribute(string name, string namespaceURI) {
199 if (m_attributes == null)
196 if (m_attributes == null)
200 return null;
197 return null;
201 var qName = new XmlQualifiedName(name, namespaceURI);
198 var qName = new XmlQualifiedName(name, namespaceURI);
202 var attr = Array.Find(m_attributes, x => x.QName == qName);
199 var attr = Array.Find(m_attributes, x => x.QName == qName);
203 var value = ConvertValueToString(attr?.Value);
200 var value = ConvertValueToString(attr?.Value);
204 return value == string.Empty ? null : value;
201 return value == string.Empty ? null : value;
205 }
202 }
206
203
207 public override string LookupNamespace(string prefix) {
204 public override string LookupNamespace(string prefix) {
208 return m_context.ResolvePrefix(prefix);
205 return m_context.ResolvePrefix(prefix);
209 }
206 }
210
207
211 public override bool MoveToAttribute(string name) {
208 public override bool MoveToAttribute(string name) {
212 if (m_attributes == null || m_attributes.Length == 0)
209 if (m_attributes == null || m_attributes.Length == 0)
213 return false;
210 return false;
214
211
215 var qName = m_context.Resolve(name);
212 var qName = m_context.Resolve(name);
216 var index = Array.FindIndex(m_attributes, x => x.QName == qName);
213 var index = Array.FindIndex(m_attributes, x => x.QName == qName);
217 if (index >= 0) {
214 if (index >= 0) {
218 MoveToAttributeImpl(index);
215 MoveToAttributeImpl(index);
219 return true;
216 return true;
220 }
217 }
221 return false;
218 return false;
222 }
219 }
223
220
224 public override bool MoveToAttribute(string name, string ns) {
221 public override bool MoveToAttribute(string name, string ns) {
225 if (m_attributes == null || m_attributes.Length == 0)
222 if (m_attributes == null || m_attributes.Length == 0)
226 return false;
223 return false;
227
224
228 var qName = m_context.Resolve(name);
225 var qName = m_context.Resolve(name);
229 var index = Array.FindIndex(m_attributes, x => x.QName == qName);
226 var index = Array.FindIndex(m_attributes, x => x.QName == qName);
230 if (index >= 0) {
227 if (index >= 0) {
231 MoveToAttributeImpl(index);
228 MoveToAttributeImpl(index);
232 return true;
229 return true;
233 }
230 }
234 return false;
231 return false;
235 }
232 }
236
233
237 void MoveToAttributeImpl(int i) {
234 void MoveToAttributeImpl(int i) {
238 if (!m_isAttribute) {
235 if (!m_isAttribute) {
239 m_elementQName = m_qName;
236 m_elementQName = m_qName;
240 m_elementDepth = m_xmlDepth;
237 m_elementDepth = m_xmlDepth;
241 m_elementPrefix = m_prefix;
238 m_elementPrefix = m_prefix;
242 m_elementIsEmpty = m_isEmpty;
239 m_elementIsEmpty = m_isEmpty;
243 m_isAttribute = true;
240 m_isAttribute = true;
244 }
241 }
245
242
246 var attr = m_attributes[i];
243 var attr = m_attributes[i];
247
244
248
245
249 m_currentAttribute = i;
246 m_currentAttribute = i;
250 m_currentAttributeRead = false;
247 m_currentAttributeRead = false;
251 m_nodeType = XmlNodeType.Attribute;
248 m_nodeType = XmlNodeType.Attribute;
252
249
253 m_xmlDepth = m_elementDepth + 1;
250 m_xmlDepth = m_elementDepth + 1;
254 m_qName = attr.QName;
251 m_qName = attr.QName;
255 m_value = attr.Value;
252 m_value = attr.Value;
256 m_prefix = attr.Prefix;
253 m_prefix = attr.Prefix;
257 }
254 }
258
255
259 public override bool MoveToElement() {
256 public override bool MoveToElement() {
260 if (m_isAttribute) {
257 if (m_isAttribute) {
261 m_value = null;
258 m_value = null;
262 m_nodeType = XmlNodeType.Element;
259 m_nodeType = XmlNodeType.Element;
263 m_xmlDepth = m_elementDepth;
260 m_xmlDepth = m_elementDepth;
264 m_prefix = m_elementPrefix;
261 m_prefix = m_elementPrefix;
265 m_qName = m_elementQName;
262 m_qName = m_elementQName;
266 m_isEmpty = m_elementIsEmpty;
263 m_isEmpty = m_elementIsEmpty;
267 m_isAttribute = false;
264 m_isAttribute = false;
268 return true;
265 return true;
269 }
266 }
270 return false;
267 return false;
271 }
268 }
272
269
273 public override bool MoveToFirstAttribute() {
270 public override bool MoveToFirstAttribute() {
274 if (m_attributes != null && m_attributes.Length > 0) {
271 if (m_attributes != null && m_attributes.Length > 0) {
275 MoveToAttributeImpl(0);
272 MoveToAttributeImpl(0);
276 return true;
273 return true;
277 }
274 }
278 return false;
275 return false;
279 }
276 }
280
277
281 public override bool MoveToNextAttribute() {
278 public override bool MoveToNextAttribute() {
282 if (m_isAttribute) {
279 if (m_isAttribute) {
283 var next = m_currentAttribute + 1;
280 var next = m_currentAttribute + 1;
284 if (next < AttributeCount) {
281 if (next < AttributeCount) {
285 MoveToAttributeImpl(next);
282 MoveToAttributeImpl(next);
286 return true;
283 return true;
287 }
284 }
288 return false;
285 return false;
289 } else {
286 } else {
290 return MoveToFirstAttribute();
287 return MoveToFirstAttribute();
291 }
288 }
292
289
293 }
290 }
294
291
295 public override bool ReadAttributeValue() {
292 public override bool ReadAttributeValue() {
296 if (!m_isAttribute || m_currentAttributeRead)
293 if (!m_isAttribute || m_currentAttributeRead)
297 return false;
294 return false;
298
295
299 ValueNode(m_attributes[m_currentAttribute].Value);
296 ValueNode(m_attributes[m_currentAttribute].Value);
300 m_currentAttributeRead = true;
297 m_currentAttributeRead = true;
301 return true;
298 return true;
302 }
299 }
303
300
304 public override void ResolveEntity() {
301 public override void ResolveEntity() {
305 /* do nothing */
302 /* do nothing */
306 }
303 }
307
304
308 /// <summary>
305 /// <summary>
309 /// Determines do we need to increase depth after the current node
306 /// Determines do we need to increase depth after the current node
310 /// </summary>
307 /// </summary>
311 /// <returns></returns>
308 /// <returns></returns>
312 public bool IsSibling() {
309 public bool IsSibling() {
313 switch (m_nodeType) {
310 switch (m_nodeType) {
314 case XmlNodeType.None: // start document
311 case XmlNodeType.None: // start document
315 case XmlNodeType.Attribute: // after attribute only it's content can be iterated with ReadAttributeValue method
312 case XmlNodeType.Attribute: // after attribute only it's content can be iterated with ReadAttributeValue method
316 return false;
313 return false;
317 case XmlNodeType.Element:
314 case XmlNodeType.Element:
318 // if the elemnt is empty the next element will be it's sibling
315 // if the elemnt is empty the next element will be it's sibling
319 return m_isEmpty;
316 return m_isEmpty;
320
317
321 case XmlNodeType.Document:
318 case XmlNodeType.Document:
322 case XmlNodeType.DocumentFragment:
319 case XmlNodeType.DocumentFragment:
323 case XmlNodeType.Entity:
320 case XmlNodeType.Entity:
324 case XmlNodeType.Text:
321 case XmlNodeType.Text:
325 case XmlNodeType.CDATA:
322 case XmlNodeType.CDATA:
326 case XmlNodeType.EntityReference:
323 case XmlNodeType.EntityReference:
327 case XmlNodeType.ProcessingInstruction:
324 case XmlNodeType.ProcessingInstruction:
328 case XmlNodeType.Comment:
325 case XmlNodeType.Comment:
329 case XmlNodeType.DocumentType:
326 case XmlNodeType.DocumentType:
330 case XmlNodeType.Notation:
327 case XmlNodeType.Notation:
331 case XmlNodeType.Whitespace:
328 case XmlNodeType.Whitespace:
332 case XmlNodeType.SignificantWhitespace:
329 case XmlNodeType.SignificantWhitespace:
333 case XmlNodeType.EndElement:
330 case XmlNodeType.EndElement:
334 case XmlNodeType.EndEntity:
331 case XmlNodeType.EndEntity:
335 case XmlNodeType.XmlDeclaration:
332 case XmlNodeType.XmlDeclaration:
336 default:
333 default:
337 return true;
334 return true;
338 }
335 }
339 }
336 }
340
337
341 void ValueNode(object value) {
338 void ValueNode(object value) {
342 if (!IsSibling()) // the node is nested
339 if (!IsSibling()) // the node is nested
343 m_xmlDepth++;
340 m_xmlDepth++;
344
341
345 m_qName = XmlQualifiedName.Empty;
342 m_qName = XmlQualifiedName.Empty;
346 m_nodeType = XmlNodeType.Text;
343 m_nodeType = XmlNodeType.Text;
347 m_prefix = string.Empty;
344 m_prefix = string.Empty;
348 m_value = value;
345 m_value = value;
349 m_isEmpty = false;
346 m_isEmpty = false;
350 m_attributes = null;
347 m_attributes = null;
351 }
348 }
352
349
353 void ElementNode(string name, string ns, XmlSimpleAttribute[] attrs, bool empty) {
350 void ElementNode(string name, string ns, XmlSimpleAttribute[] attrs, bool empty) {
354 if (!IsSibling()) // the node is nested
351 if (!IsSibling()) // the node is nested
355 m_xmlDepth++;
352 m_xmlDepth++;
356
353
357 m_context = new XmlNameContext(m_context);
354 m_context = new XmlNameContext(m_context);
358 List<XmlSimpleAttribute> definedAttrs = null;
355 List<XmlSimpleAttribute> definedAttrs = null;
359
356
360 // define new namespaces
357 // define new namespaces
361 if (attrs != null) {
358 if (attrs != null) {
362 foreach (var attr in attrs) {
359 foreach (var attr in attrs) {
363 if (attr.QName.Name == "xmlns") {
360 if (attr.QName.Name == "xmlns") {
364 m_context.DefinePrefix(ConvertValueToString(attr.Value), string.Empty);
361 m_context.DefinePrefix(ConvertValueToString(attr.Value), string.Empty);
365 } else if (attr.Prefix == m_xmlnsPrefix) {
362 } else if (attr.Prefix == m_xmlnsPrefix) {
366 m_context.DefinePrefix(ConvertValueToString(attr.Value), attr.QName.Name);
363 m_context.DefinePrefix(ConvertValueToString(attr.Value), attr.QName.Name);
367 } else {
364 } else {
368 string attrPrefix;
365 string attrPrefix;
369 if (string.IsNullOrEmpty(attr.QName.Namespace))
366 if (string.IsNullOrEmpty(attr.QName.Namespace))
370 continue;
367 continue;
371
368
372 // auto-define prefixes
369 // auto-define prefixes
373 if (!m_context.LookupNamespacePrefix(attr.QName.Namespace, out attrPrefix) || string.IsNullOrEmpty(attrPrefix)) {
370 if (!m_context.LookupNamespacePrefix(attr.QName.Namespace, out attrPrefix) || string.IsNullOrEmpty(attrPrefix)) {
374 // new namespace prefix added
371 // new namespace prefix added
375 attrPrefix = m_context.CreateNamespacePrefix(attr.QName.Namespace);
372 attrPrefix = m_context.CreateNamespacePrefix(attr.QName.Namespace);
376 attr.Prefix = attrPrefix;
373 attr.Prefix = attrPrefix;
377
374
378 if (definedAttrs == null)
375 if (definedAttrs == null)
379 definedAttrs = new List<XmlSimpleAttribute>();
376 definedAttrs = new List<XmlSimpleAttribute>();
380
377
381 definedAttrs.Add(new XmlSimpleAttribute(attrPrefix, m_xmlnsNamespace, m_xmlnsPrefix, attr.QName.Namespace));
378 definedAttrs.Add(new XmlSimpleAttribute(attrPrefix, m_xmlnsNamespace, m_xmlnsPrefix, attr.QName.Namespace));
382 }
379 }
383 }
380 }
384 }
381 }
385 }
382 }
386
383
387 string p;
384 string p;
388 // auto-define prefixes
385 // auto-define prefixes
389 if (!m_context.LookupNamespacePrefix(ns, out p)) {
386 if (!m_context.LookupNamespacePrefix(ns, out p)) {
390 p = m_context.CreateNamespacePrefix(ns);
387 p = m_context.CreateNamespacePrefix(ns);
391 if (definedAttrs == null)
388 if (definedAttrs == null)
392 definedAttrs = new List<XmlSimpleAttribute>();
389 definedAttrs = new List<XmlSimpleAttribute>();
393
390
394 definedAttrs.Add(new XmlSimpleAttribute(p, m_xmlnsNamespace, m_xmlnsPrefix, ns));
391 definedAttrs.Add(new XmlSimpleAttribute(p, m_xmlnsNamespace, m_xmlnsPrefix, ns));
395 }
392 }
396
393
397 if (definedAttrs != null) {
394 if (definedAttrs != null) {
398 if (attrs != null)
395 if (attrs != null)
399 definedAttrs.AddRange(attrs);
396 definedAttrs.AddRange(attrs);
400 attrs = definedAttrs.ToArray();
397 attrs = definedAttrs.ToArray();
401 }
398 }
402
399
403 m_nodeType = XmlNodeType.Element;
400 m_nodeType = XmlNodeType.Element;
404 m_qName = new XmlQualifiedName(name, ns);
401 m_qName = new XmlQualifiedName(name, ns);
405 m_prefix = p;
402 m_prefix = p;
406 m_value = null;
403 m_value = null;
407 m_isEmpty = empty;
404 m_isEmpty = empty;
408 m_attributes = attrs;
405 m_attributes = attrs;
409 }
406 }
410
407
411 void EndElementNode(string name, string ns) {
408 void EndElementNode(string name, string ns) {
412 if (IsSibling()) // closing the element which has children
409 if (IsSibling()) // closing the element which has children
413 m_xmlDepth--;
410 m_xmlDepth--;
414
411
415 string p;
412 string p;
416 if (!m_context.LookupNamespacePrefix(ns, out p))
413 if (!m_context.LookupNamespacePrefix(ns, out p))
417 throw new Exception($"Failed to lookup namespace '{ns}'");
414 throw new Exception($"Failed to lookup namespace '{ns}'");
418
415
419 m_context = m_context.ParentContext;
416 m_context = m_context.ParentContext;
420 m_nodeType = XmlNodeType.EndElement;
417 m_nodeType = XmlNodeType.EndElement;
421 m_prefix = p;
418 m_prefix = p;
422 m_qName = new XmlQualifiedName(name, ns);
419 m_qName = new XmlQualifiedName(name, ns);
423 m_value = null;
420 m_value = null;
424 m_attributes = null;
421 m_attributes = null;
425 m_isEmpty = false;
422 m_isEmpty = false;
426 }
423 }
427
424
428 void XmlDeclaration() {
425 void XmlDeclaration() {
429 if (!IsSibling()) // the node is nested
426 if (!IsSibling()) // the node is nested
430 m_xmlDepth++;
427 m_xmlDepth++;
431 m_nodeType = XmlNodeType.XmlDeclaration;
428 m_nodeType = XmlNodeType.XmlDeclaration;
432 m_qName = new XmlQualifiedName("xml");
429 m_qName = new XmlQualifiedName("xml");
433 m_value = "version='1.0'";
430 m_value = "version='1.0'";
434 m_prefix = string.Empty;
431 m_prefix = string.Empty;
435 m_attributes = null;
432 m_attributes = null;
436 m_isEmpty = false;
433 m_isEmpty = false;
437 }
434 }
438
435
439 public override bool Read() {
436 public override bool Read() {
440 try {
437 try {
441 string elementName;
438 string elementName;
442 XmlSimpleAttribute[] elementAttrs = null;
439 XmlSimpleAttribute[] elementAttrs = null;
443 MoveToElement();
440 MoveToElement();
444
441
445 switch (m_position) {
442 switch (m_position) {
446 case JsonXmlReaderPosition.Initial:
443 case JsonXmlReaderPosition.Initial:
447 m_jsonLocalName = m_jsonRootName;
444 m_jsonLocalName = m_jsonRootName;
448 m_jsonSkip = false;
445 m_jsonSkip = false;
449 XmlDeclaration();
446 XmlDeclaration();
450 m_position = JsonXmlReaderPosition.Declaration;
447 m_position = JsonXmlReaderPosition.Declaration;
451 return true;
448 return true;
452 case JsonXmlReaderPosition.Declaration:
449 case JsonXmlReaderPosition.Declaration:
453 elementAttrs = new[] {
450 elementAttrs = new[] {
454 new XmlSimpleAttribute(m_xsiPrefix, m_xmlnsNamespace, m_xmlnsPrefix, m_xsiNamespace),
451 new XmlSimpleAttribute(m_xsiPrefix, m_xmlnsNamespace, m_xmlnsPrefix, m_xsiNamespace),
455 string.IsNullOrEmpty(m_jsonPrefix) ?
452 string.IsNullOrEmpty(m_jsonPrefix) ?
456 new XmlSimpleAttribute(m_xmlnsPrefix, string.Empty, string.Empty, m_jsonNamespace) :
453 new XmlSimpleAttribute(m_xmlnsPrefix, string.Empty, string.Empty, m_jsonNamespace) :
457 new XmlSimpleAttribute(m_jsonPrefix, m_xmlnsNamespace, m_xmlnsPrefix, m_jsonNamespace)
454 new XmlSimpleAttribute(m_jsonPrefix, m_xmlnsNamespace, m_xmlnsPrefix, m_jsonNamespace)
458 };
455 };
459 break;
456 break;
460 case JsonXmlReaderPosition.ValueElement:
457 case JsonXmlReaderPosition.ValueElement:
461 if (!m_isEmpty) {
458 if (!m_isEmpty) {
462 ValueNode(m_parser.ElementValue);
459 ValueNode(m_parser.ElementValue);
463 m_position = JsonXmlReaderPosition.ValueContent;
460 m_position = JsonXmlReaderPosition.ValueContent;
464 return true;
461 return true;
465 } else {
462 } else {
466 m_position = JsonXmlReaderPosition.ValueEndElement;
463 m_position = JsonXmlReaderPosition.ValueEndElement;
467 break;
464 break;
468 }
465 }
469 case JsonXmlReaderPosition.ValueContent:
466 case JsonXmlReaderPosition.ValueContent:
470 EndElementNode(m_jsonValueName, m_jsonNamespace);
467 EndElementNode(m_jsonValueName, m_jsonNamespace);
471 m_position = JsonXmlReaderPosition.ValueEndElement;
468 m_position = JsonXmlReaderPosition.ValueEndElement;
472 return true;
469 return true;
473 case JsonXmlReaderPosition.Eof:
470 case JsonXmlReaderPosition.Eof:
474 case JsonXmlReaderPosition.Closed:
471 case JsonXmlReaderPosition.Closed:
475 case JsonXmlReaderPosition.Error:
472 case JsonXmlReaderPosition.Error:
476 return false;
473 return false;
477 }
474 }
478
475
479 while (m_parser.Read()) {
476 while (m_parser.Read()) {
480 var jsonName = m_nameTable.Add(m_parser.ElementName);
477 var jsonName = m_nameTable.Add(m_parser.ElementName);
481
478
482 switch (m_parser.ElementType) {
479 switch (m_parser.ElementType) {
483 case JSONElementType.BeginObject:
480 case JsonElementType.BeginObject:
484 if (!EnterJsonObject(jsonName, out elementName))
481 if (!EnterJsonObject(jsonName, out elementName))
485 continue;
482 continue;
486
483
487 m_position = JsonXmlReaderPosition.BeginObject;
484 m_position = JsonXmlReaderPosition.BeginObject;
488 ElementNode(elementName, m_jsonNamespace, elementAttrs, false);
485 ElementNode(elementName, m_jsonNamespace, elementAttrs, false);
489 break;
486 break;
490 case JSONElementType.EndObject:
487 case JsonElementType.EndObject:
491 if (!LeaveJsonScope(out elementName))
488 if (!LeaveJsonScope(out elementName))
492 continue;
489 continue;
493
490
494 m_position = JsonXmlReaderPosition.EndObject;
491 m_position = JsonXmlReaderPosition.EndObject;
495 EndElementNode(elementName, m_jsonNamespace);
492 EndElementNode(elementName, m_jsonNamespace);
496 break;
493 break;
497 case JSONElementType.BeginArray:
494 case JsonElementType.BeginArray:
498 if (!EnterJsonArray(jsonName, out elementName))
495 if (!EnterJsonArray(jsonName, out elementName))
499 continue;
496 continue;
500
497
501 m_position = JsonXmlReaderPosition.BeginArray;
498 m_position = JsonXmlReaderPosition.BeginArray;
502 ElementNode(elementName, m_jsonNamespace, elementAttrs, false);
499 ElementNode(elementName, m_jsonNamespace, elementAttrs, false);
503 break;
500 break;
504 case JSONElementType.EndArray:
501 case JsonElementType.EndArray:
505 if (!LeaveJsonScope(out elementName))
502 if (!LeaveJsonScope(out elementName))
506 continue;
503 continue;
507
504
508 m_position = JsonXmlReaderPosition.EndArray;
505 m_position = JsonXmlReaderPosition.EndArray;
509 EndElementNode(elementName, m_jsonNamespace);
506 EndElementNode(elementName, m_jsonNamespace);
510 break;
507 break;
511 case JSONElementType.Value:
508 case JsonElementType.Value:
512 if (!VisitJsonValue(jsonName, out m_jsonValueName))
509 if (!VisitJsonValue(jsonName, out m_jsonValueName))
513 continue;
510 continue;
514
511
515 m_position = JsonXmlReaderPosition.ValueElement;
512 m_position = JsonXmlReaderPosition.ValueElement;
516 if (m_parser.ElementValue == null)
513 if (m_parser.ElementValue == null)
517 // generate empty element with xsi:nil="true" attribute
514 // generate empty element with xsi:nil="true" attribute
518 ElementNode(
515 ElementNode(
519 m_jsonValueName,
516 m_jsonValueName,
520 m_jsonNamespace,
517 m_jsonNamespace,
521 new[] {
518 new[] {
522 new XmlSimpleAttribute("nil", m_xsiNamespace, m_xsiPrefix, true)
519 new XmlSimpleAttribute("nil", m_xsiNamespace, m_xsiPrefix, true)
523 },
520 },
524 true
521 true
525 );
522 );
526 else
523 else
527 ElementNode(m_jsonValueName, m_jsonNamespace, elementAttrs, m_parser.ElementValue as string == string.Empty);
524 ElementNode(m_jsonValueName, m_jsonNamespace, elementAttrs, m_parser.ElementValue as string == string.Empty);
528 break;
525 break;
529 default:
526 default:
530 throw new Exception($"Unexpected JSON element {m_parser.ElementType}: {m_parser.ElementName}");
527 throw new Exception($"Unexpected JSON element {m_parser.ElementType}: {m_parser.ElementName}");
531 }
528 }
532 return true;
529 return true;
533 }
530 }
534
531
535 m_position = JsonXmlReaderPosition.Eof;
532 m_position = JsonXmlReaderPosition.Eof;
536 return false;
533 return false;
537 } catch {
534 } catch {
538 m_position = JsonXmlReaderPosition.Error;
535 m_position = JsonXmlReaderPosition.Error;
539 throw;
536 throw;
540 }
537 }
541 }
538 }
542
539
543 void SaveJsonName() {
540 void SaveJsonName() {
544 m_jsonNameStack.Push(new JsonContext {
541 m_jsonNameStack.Push(new JsonContext {
545 skip = m_jsonSkip,
542 skip = m_jsonSkip,
546 localName = m_jsonLocalName
543 localName = m_jsonLocalName
547 });
544 });
548
545
549 }
546 }
550
547
551 bool EnterJsonObject(string name, out string elementName) {
548 bool EnterJsonObject(string name, out string elementName) {
552 SaveJsonName();
549 SaveJsonName();
553 m_jsonSkip = false;
550 m_jsonSkip = false;
554
551
555 if (string.IsNullOrEmpty(name)) {
552 if (string.IsNullOrEmpty(name)) {
556 if (m_jsonNameStack.Count != 1 && !m_jsonFlattenArrays)
553 if (m_jsonNameStack.Count != 1 && !m_jsonFlattenArrays)
557 m_jsonLocalName = m_jsonArrayItemName;
554 m_jsonLocalName = m_jsonArrayItemName;
558 } else {
555 } else {
559 m_jsonLocalName = name;
556 m_jsonLocalName = name;
560 }
557 }
561
558
562 elementName = m_jsonLocalName;
559 elementName = m_jsonLocalName;
563 return true;
560 return true;
564 }
561 }
565
562
566 /// <summary>
563 /// <summary>
567 /// Called when JSON parser visits BeginArray ('[') element.
564 /// Called when JSON parser visits BeginArray ('[') element.
568 /// </summary>
565 /// </summary>
569 /// <param name="name">Optional property name if the array is the member of an object</param>
566 /// <param name="name">Optional property name if the array is the member of an object</param>
570 /// <returns>true if element should be emited, false otherwise</returns>
567 /// <returns>true if element should be emited, false otherwise</returns>
571 bool EnterJsonArray(string name, out string elementName) {
568 bool EnterJsonArray(string name, out string elementName) {
572 SaveJsonName();
569 SaveJsonName();
573
570
574 if (string.IsNullOrEmpty(name)) {
571 if (string.IsNullOrEmpty(name)) {
575 // m_jsonNameStack.Count == 1 means the root node
572 // m_jsonNameStack.Count == 1 means the root node
576 if (m_jsonNameStack.Count != 1 && !m_jsonFlattenArrays)
573 if (m_jsonNameStack.Count != 1 && !m_jsonFlattenArrays)
577 m_jsonLocalName = m_jsonArrayItemName;
574 m_jsonLocalName = m_jsonArrayItemName;
578
575
579 m_jsonSkip = false; // we should not flatten arrays inside arrays or in the document root
576 m_jsonSkip = false; // we should not flatten arrays inside arrays or in the document root
580 } else {
577 } else {
581 m_jsonLocalName = name;
578 m_jsonLocalName = name;
582 m_jsonSkip = m_jsonFlattenArrays;
579 m_jsonSkip = m_jsonFlattenArrays;
583 }
580 }
584 elementName = m_jsonLocalName;
581 elementName = m_jsonLocalName;
585
582
586 return !m_jsonSkip;
583 return !m_jsonSkip;
587 }
584 }
588
585
589 bool VisitJsonValue(string name, out string elementName) {
586 bool VisitJsonValue(string name, out string elementName) {
590 if (string.IsNullOrEmpty(name)) {
587 if (string.IsNullOrEmpty(name)) {
591 // m_jsonNameStack.Count == 0 means that JSON document consists from simple value
588 // m_jsonNameStack.Count == 0 means that JSON document consists from simple value
592 elementName = (m_jsonNameStack.Count == 0 || m_jsonFlattenArrays) ? m_jsonLocalName : m_jsonArrayItemName;
589 elementName = (m_jsonNameStack.Count == 0 || m_jsonFlattenArrays) ? m_jsonLocalName : m_jsonArrayItemName;
593 } else {
590 } else {
594 elementName = name;
591 elementName = name;
595 }
592 }
596 return true;
593 return true;
597 }
594 }
598
595
599 bool LeaveJsonScope(out string elementName) {
596 bool LeaveJsonScope(out string elementName) {
600 elementName = m_jsonLocalName;
597 elementName = m_jsonLocalName;
601 var skip = m_jsonSkip;
598 var skip = m_jsonSkip;
602
599
603 var prev = m_jsonNameStack.Pop();
600 var prev = m_jsonNameStack.Pop();
604 m_jsonLocalName = prev.localName;
601 m_jsonLocalName = prev.localName;
605 m_jsonSkip = prev.skip;
602 m_jsonSkip = prev.skip;
606
603
607 return !skip;
604 return !skip;
608 }
605 }
609
606
610 public override string ToString() {
607 public override string ToString() {
611 switch (NodeType) {
608 switch (NodeType) {
612 case XmlNodeType.Element:
609 case XmlNodeType.Element:
613 return $"<{Name} {string.Join(" ", (m_attributes ?? new XmlSimpleAttribute[0]).Select(x => $"{x.Prefix}{(string.IsNullOrEmpty(x.Prefix) ? "" : ":")}{x.QName.Name}='{ConvertValueToString(x.Value)}'"))} {(IsEmptyElement ? "/" : "")}>";
610 return $"<{Name} {string.Join(" ", (m_attributes ?? new XmlSimpleAttribute[0]).Select(x => $"{x.Prefix}{(string.IsNullOrEmpty(x.Prefix) ? "" : ":")}{x.QName.Name}='{ConvertValueToString(x.Value)}'"))} {(IsEmptyElement ? "/" : "")}>";
614 case XmlNodeType.Attribute:
611 case XmlNodeType.Attribute:
615 return $"@{Name}";
612 return $"@{Name}";
616 case XmlNodeType.Text:
613 case XmlNodeType.Text:
617 return $"{Value}";
614 return $"{Value}";
618 case XmlNodeType.CDATA:
615 case XmlNodeType.CDATA:
619 return $"<![CDATA[{Value}]]>";
616 return $"<![CDATA[{Value}]]>";
620 case XmlNodeType.EntityReference:
617 case XmlNodeType.EntityReference:
621 return $"&{Name};";
618 return $"&{Name};";
622 case XmlNodeType.EndElement:
619 case XmlNodeType.EndElement:
623 return $"</{Name}>";
620 return $"</{Name}>";
624 default:
621 default:
625 return $".{NodeType} {Name} {Value}";
622 return $".{NodeType} {Name} {Value}";
626 }
623 }
627 }
624 }
628 }
625 }
629 }
626 }
@@ -1,66 +1,66
1
1
2 using System;
2 using System;
3 using System.Xml;
3 using System.Xml;
4
4
5 namespace Implab.Formats.JSON {
5 namespace Implab.Xml {
6 /// <summary>
6 /// <summary>
7 /// Набор необязательных параметров для <see cref="JSONXmlReader"/>, позволяющий управлять процессом
7 /// Набор необязательных параметров для <see cref="JsonXmlReader"/>, позволяющий управлять процессом
8 /// интерпретации <c>JSON</c> документа.
8 /// интерпретации <c>JSON</c> документа.
9 /// </summary>
9 /// </summary>
10 public class JSONXmlReaderOptions : ICloneable {
10 public class JsonXmlReaderOptions : ICloneable {
11 /// <summary>
11 /// <summary>
12 /// Пространство имен в котором будут располагаться читаемые элементы документа
12 /// Пространство имен в котором будут располагаться читаемые элементы документа
13 /// </summary>
13 /// </summary>
14 public string NamespaceURI {
14 public string NamespaceUri {
15 get;
15 get;
16 set;
16 set;
17 }
17 }
18
18
19 /// <summary>
19 /// <summary>
20 /// Интерпретировать массивы как множественные элементы (убирает один уровень вложенности), иначе массив
20 /// Интерпретировать массивы как множественные элементы (убирает один уровень вложенности), иначе массив
21 /// представляется в виде узла, дочерними элементами которого являются элементы массива, имена дочерних элементов
21 /// представляется в виде узла, дочерними элементами которого являются элементы массива, имена дочерних элементов
22 /// определяются свойством <see cref="ArrayItemName"/>. По умолчанию <c>false</c>.
22 /// определяются свойством <see cref="ArrayItemName"/>. По умолчанию <c>false</c>.
23 /// </summary>
23 /// </summary>
24 public bool FlattenArrays {
24 public bool FlattenArrays {
25 get;
25 get;
26 set;
26 set;
27 }
27 }
28
28
29 /// <summary>
29 /// <summary>
30 /// Префикс, для узлов документа
30 /// Префикс, для узлов документа
31 /// </summary>
31 /// </summary>
32 public string NodesPrefix {
32 public string NodesPrefix {
33 get;
33 get;
34 set;
34 set;
35 }
35 }
36
36
37 /// <summary>
37 /// <summary>
38 /// Имя корневого элемента в xml документе
38 /// Имя корневого элемента в xml документе
39 /// </summary>
39 /// </summary>
40 public string RootName {
40 public string RootName {
41 get;
41 get;
42 set;
42 set;
43 }
43 }
44
44
45 /// <summary>
45 /// <summary>
46 /// Имя элемента для массивов, если не включена опция <see cref="FlattenArrays"/>.
46 /// Имя элемента для массивов, если не включена опция <see cref="FlattenArrays"/>.
47 /// По умолчанию <c>item</c>.
47 /// По умолчанию <c>item</c>.
48 /// </summary>
48 /// </summary>
49 public string ArrayItemName {
49 public string ArrayItemName {
50 get;
50 get;
51 set;
51 set;
52 }
52 }
53
53
54 /// <summary>
54 /// <summary>
55 /// Таблица атомизированных строк для построения документа.
55 /// Таблица атомизированных строк для построения документа.
56 /// </summary>
56 /// </summary>
57 public XmlNameTable NameTable {
57 public XmlNameTable NameTable {
58 get;
58 get;
59 set;
59 set;
60 }
60 }
61
61
62 public object Clone() {
62 public object Clone() {
63 return MemberwiseClone();
63 return MemberwiseClone();
64 }
64 }
65 }
65 }
66 }
66 }
1 NO CONTENT: file was removed
NO CONTENT: file was removed
1 NO CONTENT: file was removed
NO CONTENT: file was removed
1 NO CONTENT: file was removed
NO CONTENT: file was removed
1 NO CONTENT: file was removed
NO CONTENT: file was removed
1 NO CONTENT: file was removed
NO CONTENT: file was removed
1 NO CONTENT: file was removed
NO CONTENT: file was removed
General Comments 3
Under Review
author

Auto status change to "Under Review"

Approved
author

ok, latest stable version should be in default

You need to be logged in to leave comments. Login now