1 module tagion.hibon.HiBONValid;
2 
3 import tagion.basic.Types : Buffer;
4 import tagion.hibon.Document : Document;
5 
6 bool error_callback(const Document main_doc, const Document.Element.ErrorCode error_code,
7         const(Document.Element) current, const(Document.Element) previous) nothrow @safe {
8     import tagion.hibon.HiBONBase : Type, isHiBONBaseType;
9     import LEB128 = tagion.utils.LEB128;
10     import std.exception : assumeWontThrow;
11     import std.stdio;
12     import std.traits : EnumMembers, isIntegral;
13 
14     static void hex_dump(Buffer data) {
15         import std.algorithm.comparison : min;
16 
17         uint addr;
18         enum width = 16;
19         while (data.length) {
20             writef("\t\t%04X", addr);
21             const data_size = min(data.length, width);
22             foreach (d; data[0 .. data_size]) {
23                 writef(" %02X", d);
24             }
25             writeln();
26             data = data[data_size .. $];
27             addr += width;
28         }
29     }
30 
31     try {
32         writefln("ErrorCode %s", error_code);
33         if (current.data.length) {
34             const current_pos = (() @trusted {
35                 if (current.isEod) {
36                     return size_t(0);
37                 }
38                 return size_t(current.data.ptr - main_doc.data.ptr);
39             })();
40 
41             const previous_pos = (() @trusted {
42                 if (previous.isEod) {
43                     return size_t(0);
44                 }
45                 return size_t(previous.data.ptr - main_doc.data.ptr);
46             })();
47 
48             CaseErrorCode: with (Document.Element.ErrorCode) {
49                 switch (error_code) {
50                 case DOCUMENT_OVERFLOW:
51                     return true;
52                 default:
53                     writefln("\tpos      %d", current_pos);
54                     writefln("\tType     %s", current.type);
55                     writefln("\tKeyPos   %d", current.keyPos);
56                     writefln("\tvaluePos %d", current.valuePos);
57                     writefln("\tkey      '%s'", current.key);
58                     with (Type) {
59                 CaseType:
60                         switch (current.type) {
61                             static foreach (E; EnumMembers!(Type)) {
62                         case E:
63                                 static if ((E is STRING) || (E is DOCUMENT) || (E is BINARY)) {
64                                     writefln("\tdataPos  %d", current.dataPos);
65                                     writefln("\tdataSize %d", current.dataSize);
66                                     hex_dump(current.data[current.dataPos .. current.dataSize]);
67                                 }
68                                 else static if (E is BINARY) {
69                                     const big_size = BigNumber.calc_size(data[valuePos .. $]);
70                                     writefln("\tbigSize  %d", big_size);
71                                     hex_dump(current.data[current.dataPos .. big_size]);
72                                 }
73                                 else static if (isHiBONBaseType(E)) {
74                                     static if (E is TIME) {
75                                         alias T = long;
76                                     }
77                                     else {
78                                         alias T = Document.Value.TypeT!E;
79                                     }
80                                     static if (isIntegral!T) {
81                                         const leb128_size = LEB128.calc_size(
82                                                 current.data[current.valuePos .. $]);
83                                         writefln("\tleb128  %d", leb128_size);
84                                         hex_dump(
85                                                 current.data[current.valuePos
86                                                 .. current.valuePos + leb128_size]);
87                                     }
88                                     else {
89                                         hex_dump(
90                                                 current.data[current.valuePos
91                                                 .. current.valuePos + T.sizeof]);
92                                     }
93                                 }
94                                 else static if (E is VER) {
95                                     const leb128_version_size = LEB128.calc_size(
96                                             current.data[ubyte.sizeof .. $]);
97                                     hex_dump(
98                                             current.data[ubyte.sizeof
99                                             .. ubyte.sizeof + leb128_version_size]);
100                                 }
101                                 static if (isHiBONBaseType(E)) {
102                                     (() @trusted { writefln("\tvalue  %s", current.by!E); })();
103                                 }
104 
105                                 break CaseType;
106 
107                             }
108                         default:
109                             // Empty
110                         }
111                     }
112                 }
113             }
114         }
115         return false;
116     }
117     catch (Exception e) {
118         assumeWontThrow( //        (() @trusted {
119         { stdout.flush; writefln("%s", e); });
120         //        })();
121         return true;
122     }
123     return false;
124 }