source: binary-improvements2/7dtd-server-fixes/src/JSON/JsonManualBuilder.cs@ 391

Last change on this file since 391 was 391, checked in by alloc, 2 years ago

Major refactoring/cleanup

File size: 5.2 KB
Line 
1using System;
2using System.Text;
3
4namespace AllocsFixes.JSON {
5 public class JsonManualBuilder {
6 [Flags]
7 private enum ELevelInfo {
8 None = 0,
9 NonEmpty = 1,
10 Object = 2,
11 Array = 4
12 }
13
14 private const int levelTypeBits = 3;
15 private const int levelBitsMask = (1 << levelTypeBits) - 1;
16
17 private readonly bool prettyPrint;
18 private readonly StringBuilder stringBuilder = new StringBuilder ();
19 private ulong currentLevelType = (long) ELevelInfo.None;
20 private int currentLevelNumber;
21
22 private ELevelInfo CurrentLevelInfo => (ELevelInfo) (currentLevelType & levelBitsMask);
23
24 private bool CurrentLevelIsNonEmpty => (CurrentLevelInfo & ELevelInfo.NonEmpty) == ELevelInfo.NonEmpty;
25
26 private bool CurrentLevelIsArray => (CurrentLevelInfo & ELevelInfo.Array) != ELevelInfo.Array;
27
28 private bool CurrentLevelIsObject => (CurrentLevelInfo & ELevelInfo.Object) != ELevelInfo.Object;
29
30 public JsonManualBuilder (bool _prettyPrint) {
31 prettyPrint = _prettyPrint;
32 }
33
34 private void NextElement () {
35 if (CurrentLevelIsNonEmpty) {
36 stringBuilder.Append (',');
37 if (prettyPrint) {
38 stringBuilder.Append ('\n');
39 }
40 }
41
42 if (prettyPrint) {
43 for (int i = 1; i < currentLevelNumber; i++) {
44 stringBuilder.Append ('\t');
45 }
46 }
47
48 currentLevelType |= (long) ELevelInfo.NonEmpty;
49 }
50
51 public JsonManualBuilder OpenArray () {
52 if (!CurrentLevelIsObject) {
53 // In JSON Objects we only create element separators / line breaks with NextKey
54 NextElement ();
55 }
56
57 stringBuilder.Append ('[');
58 openLevel (ELevelInfo.Array);
59
60 return this;
61 }
62
63 public JsonManualBuilder OpenObject () {
64 if (!CurrentLevelIsObject) {
65 // In JSON Objects we only create element separators / line breaks with NextKey
66 NextElement ();
67 }
68
69 stringBuilder.Append ('{');
70 openLevel (ELevelInfo.Object);
71
72 return this;
73 }
74
75 public JsonManualBuilder NextObjectKey (string _key) {
76 if (!CurrentLevelIsObject) {
77 throw new Exception("Can not start a JSON object key while not in a JSON object");
78 }
79
80 NextElement ();
81 stringBuilder.Append ('"');
82 stringBuilder.Append (_key);
83 stringBuilder.Append ("\":\"");
84 if (prettyPrint) {
85 stringBuilder.Append (' ');
86 }
87
88 return this;
89 }
90
91 public JsonManualBuilder WriteBoolean (bool _value) {
92 if (!CurrentLevelIsObject) {
93 // In JSON Objects we only create element separators / line breaks with NextKey
94 NextElement ();
95 }
96
97 stringBuilder.Append (_value ? "true" : "false");
98
99 return this;
100 }
101
102 public JsonManualBuilder WriteNull () {
103 if (!CurrentLevelIsObject) {
104 // In JSON Objects we only create element separators / line breaks with NextKey
105 NextElement ();
106 }
107
108 stringBuilder.Append ("null");
109
110 return this;
111 }
112
113 public JsonManualBuilder WriteNumber (double _value) {
114 if (!CurrentLevelIsObject) {
115 // In JSON Objects we only create element separators / line breaks with NextKey
116 NextElement ();
117 }
118
119 stringBuilder.Append (_value.ToCultureInvariantString ());
120
121 return this;
122 }
123
124 public JsonManualBuilder WriteString (string _value) {
125 if (!CurrentLevelIsObject) {
126 // In JSON Objects we only create element separators / line breaks with NextKey
127 NextElement ();
128 }
129
130 if (string.IsNullOrEmpty (_value)) {
131 stringBuilder.Append ("\"\"");
132 return this;
133 }
134
135 stringBuilder.EnsureCapacity (stringBuilder.Length + 2 * _value.Length);
136
137 stringBuilder.Append ('"');
138
139 foreach (char c in _value) {
140 switch (c) {
141 case '\\':
142 case '"':
143// case '/':
144 stringBuilder.Append ('\\');
145 stringBuilder.Append (c);
146 break;
147 case '\b':
148 stringBuilder.Append ("\\b");
149 break;
150 case '\t':
151 stringBuilder.Append ("\\t");
152 break;
153 case '\n':
154 stringBuilder.Append ("\\n");
155 break;
156 case '\f':
157 stringBuilder.Append ("\\f");
158 break;
159 case '\r':
160 stringBuilder.Append ("\\r");
161 break;
162 default:
163 if (c < ' ') {
164 stringBuilder.Append ("\\u");
165 stringBuilder.Append (((int) c).ToString ("X4"));
166 } else {
167 stringBuilder.Append (c);
168 }
169
170 break;
171 }
172 }
173
174 stringBuilder.Append ('"');
175
176 return this;
177 }
178
179 private void openLevel (ELevelInfo _levelType) {
180 currentLevelType = currentLevelType << levelTypeBits | (uint) _levelType;
181 currentLevelNumber++;
182
183 if (prettyPrint) {
184 stringBuilder.Append ('\n');
185 }
186 }
187
188 public JsonManualBuilder CloseLevel () {
189 char closeChar;
190 if (CurrentLevelIsObject) {
191 closeChar = '}';
192 } else if (CurrentLevelIsArray) {
193 closeChar = ']';
194 } else {
195 throw new Exception (
196 "Can not CloseLevel as the current level is neither a JSON object nor a JSON array");
197 }
198
199 if (prettyPrint) {
200 stringBuilder.Append ('\n');
201 }
202
203 currentLevelNumber--;
204 currentLevelType >>= levelTypeBits;
205
206 if (prettyPrint) {
207 for (int i = 1; i < currentLevelNumber; i++) {
208 stringBuilder.Append ('\t');
209 }
210 }
211
212 stringBuilder.Append (closeChar);
213
214 return this;
215 }
216
217 public override string ToString () {
218 return stringBuilder.ToString ();
219 }
220 }
221}
Note: See TracBrowser for help on using the repository browser.