deukpack 1.0.1 → 1.0.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,432 @@
1
+ /**
2
+ * DpJsonProtocol — JSON 프로토콜. DpProtocolLibrary 모듈화.
3
+ */
4
+
5
+ using System;
6
+ using System.Collections.Generic;
7
+ using System.IO;
8
+ using System.Text;
9
+
10
+ namespace DeukPack.Protocol
11
+ {
12
+ /// <summary>
13
+ /// JSON protocol (TJSONProtocol-compatible).
14
+ /// Stream-based; constructor(stream, includeSchema, isReadMode).
15
+ /// </summary>
16
+ public class DpJsonProtocol : DpProtocol
17
+ {
18
+ private readonly Stream _stream;
19
+ private readonly bool _isReadMode;
20
+ private readonly bool _includeSchema;
21
+ private readonly Stack<JsonStructState> _writeStack;
22
+ private readonly Stack<List<object>> _listWriteStack;
23
+ private readonly Stack<MapWriteState> _mapWriteStack;
24
+ private string _currentFieldKey;
25
+ private DpWireType _currentFieldType;
26
+ private Dictionary<string, object> _rootRead;
27
+ private Stack<JsonReadCursor> _readStack;
28
+ private KeyValuePair<string, object>? _currentReadField;
29
+ private List<object> _readList;
30
+ private int _readListIndex;
31
+ private Dictionary<string, object> _readMapDict;
32
+ private List<string> _readMapKeys;
33
+ private int _readMapIndex;
34
+ private bool _readMapReadingKey;
35
+ private string _readMapCurrentKey;
36
+ private readonly UTF8Encoding _utf8 = new UTF8Encoding(false);
37
+
38
+ public DpJsonProtocol(Stream stream, bool includeSchema = false, bool isReadMode = true)
39
+ {
40
+ _stream = stream ?? throw new ArgumentNullException(nameof(stream));
41
+ _includeSchema = includeSchema;
42
+ _isReadMode = isReadMode;
43
+ _writeStack = new Stack<JsonStructState>();
44
+ _listWriteStack = new Stack<List<object>>();
45
+ _mapWriteStack = new Stack<MapWriteState>();
46
+ _readStack = new Stack<JsonReadCursor>();
47
+ if (isReadMode)
48
+ {
49
+ using (var sr = new StreamReader(stream, _utf8, false, 4096, true))
50
+ {
51
+ var json = sr.ReadToEnd();
52
+ _rootRead = JsonProtocolParse(json);
53
+ }
54
+ }
55
+ }
56
+
57
+ private struct JsonStructState
58
+ {
59
+ public Dictionary<string, object> Obj;
60
+ public bool IsMapKey;
61
+ }
62
+
63
+ private struct JsonReadCursor
64
+ {
65
+ public Dictionary<string, object> Obj;
66
+ public IEnumerator<KeyValuePair<string, object>> Enumerator;
67
+ }
68
+
69
+ private class MapWriteState
70
+ {
71
+ public readonly Dictionary<string, object> Map = new Dictionary<string, object>();
72
+ public object PendingKey;
73
+ }
74
+
75
+ private static string DpWireTypeToJsonKey(DpWireType t)
76
+ {
77
+ return DpTypeNames.ToProtocolName(t);
78
+ }
79
+
80
+ private static object WrapValueForJson(object value)
81
+ {
82
+ if (value == null) return null;
83
+ if (value is Dictionary<string, object> d) return d;
84
+ if (value is List<object> l) return new Dictionary<string, object> { { "lst", l } };
85
+ if (value is bool b) return new Dictionary<string, object> { { "tf", b } };
86
+ if (value is int || value is long || value is short || value is byte) return new Dictionary<string, object> { { "i64", Convert.ToInt64(value) } };
87
+ if (value is double db) return new Dictionary<string, object> { { "dbl", db } };
88
+ return new Dictionary<string, object> { { "str", value.ToString() } };
89
+ }
90
+
91
+ private void WriteValueToCurrent(object value)
92
+ {
93
+ if (_mapWriteStack.Count > 0)
94
+ {
95
+ var top = _mapWriteStack.Peek();
96
+ if (top.PendingKey == null)
97
+ top.PendingKey = value;
98
+ else
99
+ {
100
+ var keyStr = top.PendingKey?.ToString() ?? "";
101
+ top.Map[keyStr] = WrapValueForJson(value);
102
+ top.PendingKey = null;
103
+ }
104
+ return;
105
+ }
106
+ if (_listWriteStack.Count > 0)
107
+ {
108
+ _listWriteStack.Peek().Add(value);
109
+ return;
110
+ }
111
+ var wrapper = new Dictionary<string, object> { { DpWireTypeToJsonKey(_currentFieldType), value } };
112
+ _writeStack.Peek().Obj[_currentFieldKey] = wrapper;
113
+ }
114
+
115
+ public void WriteStructBegin(DpRecord s) { _writeStack.Push(new JsonStructState { Obj = new Dictionary<string, object>(), IsMapKey = false }); }
116
+ public void WriteStructEnd()
117
+ {
118
+ var top = _writeStack.Pop();
119
+ if (_mapWriteStack.Count > 0)
120
+ {
121
+ var outer = _mapWriteStack.Peek();
122
+ outer.Map[outer.PendingKey?.ToString() ?? ""] = top.Obj;
123
+ outer.PendingKey = null;
124
+ }
125
+ else if (_listWriteStack.Count > 0)
126
+ _listWriteStack.Peek().Add(top.Obj);
127
+ else if (_writeStack.Count > 0)
128
+ _writeStack.Peek().Obj[_currentFieldKey] = top.Obj;
129
+ else
130
+ {
131
+ var json = JsonProtocolSerialize(top.Obj);
132
+ var bytes = _utf8.GetBytes(json);
133
+ _stream.Write(bytes, 0, bytes.Length);
134
+ _stream.Flush();
135
+ }
136
+ }
137
+ public void WriteFieldBegin(DpColumn f) { _currentFieldKey = f.ID.ToString(); _currentFieldType = f.Type; }
138
+ public void WriteFieldEnd() { }
139
+ public void WriteFieldStop() { }
140
+ public void WriteBool(bool b) { WriteValueToCurrent(b); }
141
+ public void WriteByte(byte b) { WriteValueToCurrent((int)b); }
142
+ public void WriteI16(short v) { WriteValueToCurrent(v); }
143
+ public void WriteI32(int v) { WriteValueToCurrent(v); }
144
+ public void WriteI64(long v) { WriteValueToCurrent(v); }
145
+ public void WriteDouble(double v) { WriteValueToCurrent(v); }
146
+ public void WriteString(string s) { WriteValueToCurrent(s ?? ""); }
147
+ public void WriteBinary(byte[] b) { WriteValueToCurrent(Convert.ToBase64String(b ?? Array.Empty<byte>())); }
148
+ public void WriteListBegin(DpList list) { _listWriteStack.Push(new List<object>()); }
149
+ public void WriteListEnd()
150
+ {
151
+ var list = _listWriteStack.Pop();
152
+ var wrapper = new Dictionary<string, object> { { "lst", list } };
153
+ if (_mapWriteStack.Count > 0)
154
+ {
155
+ var outer = _mapWriteStack.Peek();
156
+ outer.Map[outer.PendingKey?.ToString() ?? ""] = wrapper;
157
+ outer.PendingKey = null;
158
+ }
159
+ else if (_listWriteStack.Count > 0)
160
+ _listWriteStack.Peek().Add(list);
161
+ else
162
+ _writeStack.Peek().Obj[_currentFieldKey] = wrapper;
163
+ }
164
+ public void WriteSetBegin(DpSet set) { WriteListBegin(new DpList { ElementType = set.ElementType, Count = set.Count }); }
165
+ public void WriteSetEnd() { WriteListEnd(); }
166
+ public void WriteMapBegin(DpDict map) { _mapWriteStack.Push(new MapWriteState()); }
167
+ public void WriteMapEnd()
168
+ {
169
+ var state = _mapWriteStack.Pop();
170
+ var wrapper = new Dictionary<string, object> { { "map", state.Map } };
171
+ if (_mapWriteStack.Count > 0)
172
+ {
173
+ var outer = _mapWriteStack.Peek();
174
+ outer.Map[outer.PendingKey?.ToString() ?? ""] = wrapper;
175
+ outer.PendingKey = null;
176
+ }
177
+ else if (_listWriteStack.Count > 0)
178
+ _listWriteStack.Peek().Add(wrapper);
179
+ else
180
+ _writeStack.Peek().Obj[_currentFieldKey] = wrapper;
181
+ }
182
+
183
+ public DpRecord ReadStructBegin()
184
+ {
185
+ if (_readStack.Count == 0)
186
+ _readStack.Push(new JsonReadCursor { Obj = _rootRead, Enumerator = _rootRead?.GetEnumerator() });
187
+ else if (_readList != null && _readListIndex < _readList.Count)
188
+ {
189
+ var nextObj = _readList[_readListIndex++] as Dictionary<string, object>;
190
+ if (nextObj != null)
191
+ _readStack.Push(new JsonReadCursor { Obj = nextObj, Enumerator = nextObj.GetEnumerator() });
192
+ }
193
+ else if (_readMapDict != null && !_readMapReadingKey && _readMapIndex < _readMapKeys.Count)
194
+ {
195
+ var mapVal = _readMapDict[_readMapCurrentKey];
196
+ if (mapVal is Dictionary<string, object> mapStruct)
197
+ {
198
+ _readStack.Push(new JsonReadCursor { Obj = mapStruct, Enumerator = mapStruct.GetEnumerator() });
199
+ _readMapIndex++;
200
+ _readMapReadingKey = true;
201
+ }
202
+ }
203
+ else if (_currentReadField.HasValue && _currentReadField.Value.Value is Dictionary<string, object> nextObj)
204
+ _readStack.Push(new JsonReadCursor { Obj = nextObj, Enumerator = nextObj.GetEnumerator() });
205
+ return new DpRecord("");
206
+ }
207
+ public void ReadStructEnd() { if (_readStack.Count > 0) _readStack.Pop(); }
208
+ public DpColumn ReadFieldBegin()
209
+ {
210
+ if (_readStack.Count == 0)
211
+ return new DpColumn("", DpWireType.Stop, 0);
212
+ var cur = _readStack.Peek();
213
+ if (cur.Enumerator == null || !cur.Enumerator.MoveNext())
214
+ return new DpColumn("", DpWireType.Stop, 0);
215
+ var kv = cur.Enumerator.Current;
216
+ var wrapper = kv.Value as Dictionary<string, object>;
217
+ if (wrapper == null) { _currentReadField = kv; return new DpColumn(kv.Key, DpWireType.String, 0); }
218
+ DpWireType t = DpWireType.Stop;
219
+ foreach (var key in wrapper.Keys)
220
+ {
221
+ t = DpTypeNames.FromProtocolName(key);
222
+ break;
223
+ }
224
+ _currentReadField = kv;
225
+ if ((t == DpWireType.List || t == DpWireType.Set) && wrapper.TryGetValue(DpTypeNames.ToProtocolName(t), out var listVal) && listVal is List<object> list)
226
+ {
227
+ _readList = list;
228
+ _readListIndex = 0;
229
+ }
230
+ else if (t == DpWireType.Map && wrapper.TryGetValue(DpTypeNames.ToProtocolName(t), out var mapVal) && mapVal is Dictionary<string, object> mapDict)
231
+ {
232
+ _readMapDict = mapDict;
233
+ _readMapKeys = new List<string>(mapDict.Keys);
234
+ _readMapIndex = 0;
235
+ _readMapReadingKey = true;
236
+ }
237
+ return new DpColumn(kv.Key, t, short.TryParse(kv.Key, out var id) ? id : (short)0);
238
+ }
239
+ public void ReadFieldEnd() { }
240
+ public bool ReadBool() { return ReadSingleValue<bool>("tf"); }
241
+ public byte ReadByte() { return (byte)ReadSingleValue<long>("i8"); }
242
+ public short ReadI16() { return (short)ReadSingleValue<long>("i16"); }
243
+ public int ReadI32() { return (int)ReadSingleValue<long>("i32"); }
244
+ public long ReadI64() { return ReadSingleValue<long>("i64"); }
245
+ public double ReadDouble() { return ReadSingleValue<double>("dbl"); }
246
+ public string ReadString() { return ReadSingleValue<string>("str") ?? ""; }
247
+ public byte[] ReadBinary() { var s = ReadSingleValue<string>("str"); return string.IsNullOrEmpty(s) ? Array.Empty<byte>() : Convert.FromBase64String(s); }
248
+ private T ReadSingleValue<T>(string key)
249
+ {
250
+ object v = null;
251
+ if (_readMapDict != null && _readMapIndex < _readMapKeys.Count)
252
+ {
253
+ if (_readMapReadingKey)
254
+ {
255
+ v = _readMapCurrentKey = _readMapKeys[_readMapIndex];
256
+ _readMapReadingKey = false;
257
+ }
258
+ else
259
+ {
260
+ var valObj = _readMapDict[_readMapCurrentKey];
261
+ if (valObj is Dictionary<string, object> dict)
262
+ {
263
+ if (dict.TryGetValue(key, out v)) { }
264
+ else if (dict.TryGetValue("i32", out v) || dict.TryGetValue("i64", out v) || dict.TryGetValue("i8", out v) || dict.TryGetValue("i16", out v)) { }
265
+ else if (dict.TryGetValue("str", out v)) { }
266
+ else if (dict.TryGetValue("dbl", out v)) { }
267
+ else if (dict.TryGetValue("tf", out v)) { }
268
+ }
269
+ else
270
+ v = valObj;
271
+ _readMapIndex++;
272
+ _readMapReadingKey = true;
273
+ }
274
+ }
275
+ else if (_readList != null && _readListIndex < _readList.Count)
276
+ {
277
+ var raw = _readList[_readListIndex++];
278
+ if (raw is Dictionary<string, object> dict)
279
+ {
280
+ if (dict.TryGetValue(key, out v)) { }
281
+ else if (dict.TryGetValue("i32", out v) || dict.TryGetValue("i64", out v) || dict.TryGetValue("i8", out v) || dict.TryGetValue("i16", out v)) { }
282
+ else if (dict.TryGetValue("str", out v)) { }
283
+ else if (dict.TryGetValue("dbl", out v)) { }
284
+ else if (dict.TryGetValue("tf", out v)) { }
285
+ }
286
+ else
287
+ v = raw;
288
+ }
289
+ else if (_currentReadField.HasValue)
290
+ {
291
+ var wrapper = _currentReadField.Value.Value as Dictionary<string, object>;
292
+ if (wrapper != null) wrapper.TryGetValue(key, out v);
293
+ }
294
+ if (v == null) return default;
295
+ if (typeof(T) == typeof(string)) return (T)(object)v.ToString();
296
+ if (typeof(T) == typeof(bool)) return (T)(object)Convert.ToBoolean(v);
297
+ if (typeof(T) == typeof(long)) return (T)(object)Convert.ToInt64(v);
298
+ if (typeof(T) == typeof(double)) return (T)(object)Convert.ToDouble(v);
299
+ return default;
300
+ }
301
+ public DpList ReadListBegin()
302
+ {
303
+ int c = _readList?.Count ?? 0;
304
+ return new DpList { ElementType = DpWireType.String, Count = c };
305
+ }
306
+ public void ReadListEnd() { _readList = null; }
307
+ public DpSet ReadSetBegin() { var l = ReadListBegin(); return new DpSet { ElementType = l.ElementType, Count = l.Count }; }
308
+ public void ReadSetEnd() { }
309
+ public DpDict ReadMapBegin()
310
+ {
311
+ int c = _readMapDict?.Count ?? 0;
312
+ return new DpDict { KeyType = DpWireType.String, ValueType = DpWireType.String, Count = c };
313
+ }
314
+ public void ReadMapEnd() { _readMapDict = null; _readMapKeys = null; }
315
+
316
+ private static string JsonProtocolSerialize(Dictionary<string, object> obj)
317
+ {
318
+ var sb = new StringBuilder();
319
+ sb.Append('{');
320
+ var first = true;
321
+ foreach (var kv in obj)
322
+ {
323
+ if (!first) sb.Append(',');
324
+ first = false;
325
+ sb.Append('"').Append(EscapeJson(kv.Key)).Append("\":");
326
+ AppendJsonValue(sb, kv.Value);
327
+ }
328
+ sb.Append('}');
329
+ return sb.ToString();
330
+ }
331
+ private static void AppendJsonValue(StringBuilder sb, object v)
332
+ {
333
+ if (v == null) { sb.Append("null"); return; }
334
+ if (v is bool b) { sb.Append(b ? "true" : "false"); return; }
335
+ if (v is int i) { sb.Append(i); return; }
336
+ if (v is long l) { sb.Append(l); return; }
337
+ if (v is double d) { sb.Append(d.ToString("R", System.Globalization.CultureInfo.InvariantCulture)); return; }
338
+ if (v is string s) { sb.Append('"').Append(EscapeJson(s)).Append('"'); return; }
339
+ if (v is Dictionary<string, object> dict) { sb.Append(JsonProtocolSerialize(dict)); return; }
340
+ if (v is List<object> list)
341
+ {
342
+ sb.Append('[');
343
+ for (int j = 0; j < list.Count; j++) { if (j > 0) sb.Append(','); AppendJsonValue(sb, list[j]); }
344
+ sb.Append(']');
345
+ return;
346
+ }
347
+ sb.Append("null");
348
+ }
349
+ private static string EscapeJson(string s)
350
+ {
351
+ if (string.IsNullOrEmpty(s)) return "";
352
+ return s.Replace("\\", "\\\\").Replace("\"", "\\\"").Replace("\n", "\\n").Replace("\r", "\\r").Replace("\t", "\\t");
353
+ }
354
+ private static Dictionary<string, object> JsonProtocolParse(string json)
355
+ {
356
+ if (string.IsNullOrWhiteSpace(json)) return new Dictionary<string, object>();
357
+ int i = 0;
358
+ return ParseObject(json, ref i);
359
+ }
360
+ private static Dictionary<string, object> ParseObject(string s, ref int i)
361
+ {
362
+ var obj = new Dictionary<string, object>();
363
+ SkipWs(s, ref i);
364
+ if (i >= s.Length || s[i] != '{') return obj;
365
+ i++;
366
+ while (i < s.Length)
367
+ {
368
+ SkipWs(s, ref i);
369
+ if (i < s.Length && s[i] == '}') { i++; return obj; }
370
+ var key = ParseString(s, ref i);
371
+ SkipWs(s, ref i);
372
+ if (i < s.Length && s[i] == ':') i++;
373
+ SkipWs(s, ref i);
374
+ var val = ParseValue(s, ref i);
375
+ obj[key] = val;
376
+ SkipWs(s, ref i);
377
+ if (i < s.Length && s[i] == ',') i++;
378
+ }
379
+ return obj;
380
+ }
381
+ private static object ParseValue(string s, ref int i)
382
+ {
383
+ SkipWs(s, ref i);
384
+ if (i >= s.Length) return null;
385
+ if (s[i] == '{') return ParseObject(s, ref i);
386
+ if (s[i] == '[') return ParseArray(s, ref i);
387
+ if (s[i] == '"') return ParseString(s, ref i);
388
+ if (s[i] == 't' || s[i] == 'f') return ParseBool(s, ref i);
389
+ if (s[i] == 'n') { ParseToken(s, ref i, "null"); return null; }
390
+ return ParseNumber(s, ref i);
391
+ }
392
+ private static List<object> ParseArray(string s, ref int i)
393
+ {
394
+ var list = new List<object>();
395
+ if (i >= s.Length || s[i] != '[') return list;
396
+ i++;
397
+ SkipWs(s, ref i);
398
+ while (i < s.Length && s[i] != ']')
399
+ {
400
+ list.Add(ParseValue(s, ref i));
401
+ SkipWs(s, ref i);
402
+ if (i < s.Length && s[i] == ',') i++;
403
+ }
404
+ if (i < s.Length) i++;
405
+ return list;
406
+ }
407
+ private static string ParseString(string s, ref int i)
408
+ {
409
+ if (i >= s.Length || s[i] != '"') return "";
410
+ i++;
411
+ var sb = new StringBuilder();
412
+ while (i < s.Length && s[i] != '"')
413
+ {
414
+ if (s[i] == '\\') { i++; if (i < s.Length) sb.Append(s[i++]); }
415
+ else sb.Append(s[i++]);
416
+ }
417
+ if (i < s.Length) i++;
418
+ return sb.ToString();
419
+ }
420
+ private static bool ParseBool(string s, ref int i) { if (ParseToken(s, ref i, "true")) return true; ParseToken(s, ref i, "false"); return false; }
421
+ private static bool ParseToken(string s, ref int i, string tok) { int start = i; foreach (var c in tok) { if (i < s.Length && s[i] == c) i++; else { i = start; return false; } } return true; }
422
+ private static object ParseNumber(string s, ref int i)
423
+ {
424
+ int start = i;
425
+ if (i < s.Length && (s[i] == '-' || s[i] == '+')) i++;
426
+ while (i < s.Length && char.IsDigit(s[i])) i++;
427
+ if (i < s.Length && s[i] == '.') { i++; while (i < s.Length && char.IsDigit(s[i])) i++; return double.Parse(s.Substring(start, i - start), System.Globalization.CultureInfo.InvariantCulture); }
428
+ return long.Parse(s.Substring(start, i - start), System.Globalization.CultureInfo.InvariantCulture);
429
+ }
430
+ private static void SkipWs(string s, ref int i) { while (i < s.Length && char.IsWhiteSpace(s[i])) i++; }
431
+ }
432
+ }