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 }