bert.d 9.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392
  1. import std.stdio;
  2. private{
  3. import std.conv;
  4. import std.bitmanip;
  5. import std.string;
  6. import std.utf;
  7. import std.math;
  8. import std.traits;
  9. import std.algorithm;
  10. import std.range;
  11. import std.digest : toHexString;
  12. import std.array : appender;
  13. import std.format : format;
  14. }
  15. enum BERT_TAG : ubyte{
  16. VERSION = 131,
  17. SMALL_INT = 97,
  18. INT = 98,
  19. BIGINT = 110,
  20. LARGE_BIG = 111,
  21. FLOAT = 70,
  22. ATOM = 118,
  23. TUPLE = 104, // SMALL_TUPLE
  24. LARGE_TUPLE = 105,
  25. NIL = 106,
  26. LIST = 108,
  27. BINARY = 109, // use BINARY as STRING
  28. MAP = 116
  29. }
  30. enum BertType{
  31. Int,
  32. Float,
  33. Atom,
  34. Tuple,
  35. List,
  36. Binary,
  37. Map,
  38. Nil
  39. }
  40. struct BertValue{
  41. BertType type_;
  42. union{
  43. long intValue;
  44. double floatValue;
  45. string atomValue;
  46. BertValue[] tupleValue;
  47. BertValue[] listValue;
  48. ubyte[] binaryValue;
  49. BertValue[BertValue] mapValue;
  50. }
  51. ubyte[] encode() const{
  52. final switch(type_){
  53. case BertType.Int:
  54. return encodeInt(intValue);
  55. case BertType.Float:
  56. return encodeFloat(floatValue);
  57. case BertType.Atom:
  58. return encodeAtom(atomValue);
  59. case BertType.Tuple:
  60. return encodeTuple(tupleValue.dup);
  61. case BertType.List:
  62. return encodeList(listValue.dup);
  63. case BertType.Binary:
  64. return encodeBinary(binaryValue.dup);
  65. case BertType.Map:
  66. return encodeMap(mapValue.dup);
  67. case BertType.Nil:
  68. return [cast(ubyte)BERT_TAG.NIL];
  69. }
  70. }
  71. string toString() const{
  72. final switch(type_){
  73. case BertType.Int:
  74. return to!string(intValue);
  75. case BertType.Float:
  76. return to!string(floatValue);
  77. case BertType.Atom:
  78. return format("'%s'", atomValue);
  79. case BertType.Tuple:
  80. return "{" ~ tupleValue.map!(e => e.toString()).join(", ") ~ "}";
  81. case BertType.List:
  82. return "[" ~ listValue.map!(e => e.toString()).join(", ") ~ "]";
  83. case BertType.Binary:
  84. auto result = appender!string();
  85. result.put("<<");
  86. foreach(i, b; binaryValue){
  87. if(i > 0){ result.put(","); }
  88. //result.put(format("%02X", b)); // string bytes in hex = <<"blabla">> = <<62,6C,61,62,6C,61>>
  89. result.put(to!string(b)); // string bytes in dec (like in erlang) = <<"blabla">> = <<98,108,97,98,108,97>>
  90. }
  91. result.put(">>");
  92. return result.data;
  93. case BertType.Map:
  94. string[] pairs;
  95. foreach(key, value; mapValue){
  96. pairs ~= format("%s: %s", key.toString(), value.toString());
  97. }
  98. return "#{" ~ pairs.join(", ") ~ "}";
  99. case BertType.Nil:
  100. return "[]";
  101. }
  102. }
  103. }
  104. ubyte[] bertEncode(BertValue term){
  105. return [cast(ubyte)BERT_TAG.VERSION] ~ term.encode();
  106. }
  107. ubyte[] encodeInt(long value){
  108. if(value >= 0 && value <= 255){
  109. return [cast(ubyte)BERT_TAG.SMALL_INT, cast(ubyte)value];
  110. }else if(value >= -2147483648 && value <= 2147483647){
  111. ubyte[4] bytes = nativeToBigEndian!int(cast(int)value);
  112. return [cast(ubyte)BERT_TAG.INT] ~ bytes[];
  113. }else{
  114. return encodeBigInt(value);
  115. }
  116. }
  117. ubyte[] encodeBigInt(long value){
  118. bool isNegative = (value < 0);
  119. ulong absValue = isNegative ? (-value) : value;
  120. ubyte[8] temp;
  121. size_t len = 0;
  122. while(absValue > 0){
  123. temp[len++] = cast(ubyte)(absValue & 0xFF);
  124. absValue >>= 8;
  125. }
  126. ubyte[] result = [
  127. cast(ubyte)BERT_TAG.BIGINT,
  128. cast(ubyte)len,
  129. isNegative ? 1 : 0
  130. ];
  131. foreach_reverse(i; 0..len){
  132. result ~= temp[i];
  133. }
  134. return result;
  135. }
  136. ubyte[] encodeFloat(double value){
  137. ubyte[8] bytes = nativeToBigEndian!double(value);
  138. return [cast(ubyte)BERT_TAG.FLOAT] ~ bytes[];
  139. }
  140. ubyte[] encodeAtom(string name){
  141. if(name.length > 255){ throw new Exception("Atom too long"); }
  142. return [
  143. cast(ubyte)BERT_TAG.ATOM,
  144. cast(ubyte)(name.length >> 8),
  145. cast(ubyte)(name.length & 0xFF)
  146. ] ~ cast(ubyte[])name;
  147. }
  148. ubyte[] encodeTuple(BertValue[] elements){
  149. ubyte[] result;
  150. if(elements.length <= 255){
  151. result = [cast(ubyte)BERT_TAG.TUPLE, cast(ubyte)elements.length];
  152. }else{
  153. result = [cast(ubyte)BERT_TAG.LARGE_TUPLE] ~ nativeToBigEndian!uint(cast(uint)elements.length);
  154. }
  155. foreach(elem; elements){
  156. result ~= elem.encode();
  157. }
  158. return result;
  159. }
  160. ubyte[] encodeList(BertValue[] elements){
  161. ubyte[4] lenBytes = nativeToBigEndian!uint(cast(uint)elements.length);
  162. return [cast(ubyte)BERT_TAG.LIST] ~ lenBytes[] ~ elements.map!(e => e.encode()).join() ~ cast(ubyte)BERT_TAG.NIL;
  163. }
  164. ubyte[] encodeBinary(ubyte[] data){
  165. ubyte[4] lenBytes = nativeToBigEndian!uint(cast(uint)data.length);
  166. return [cast(ubyte)BERT_TAG.BINARY] ~ lenBytes[] ~ data;
  167. }
  168. ubyte[] encodeMap(const BertValue[BertValue] map){
  169. ubyte[4] lenBytes = nativeToBigEndian!uint(cast(uint)map.length);
  170. return [cast(ubyte)BERT_TAG.MAP] ~ lenBytes[] ~ map.byPair.map!(p => p.key.encode() ~ p.value.encode()).join();
  171. }
  172. BertValue bertInt(long value){
  173. BertValue v;
  174. v.type_ = BertType.Int;
  175. v.intValue = value;
  176. return v;
  177. }
  178. BertValue bertFloat(double value){
  179. BertValue v;
  180. v.type_ = BertType.Float;
  181. v.floatValue = value;
  182. return v;
  183. }
  184. BertValue bertAtom(string name){
  185. BertValue v;
  186. v.type_ = BertType.Atom;
  187. v.atomValue = name;
  188. return v;
  189. }
  190. BertValue bertBinary(ubyte[] data){
  191. BertValue v;
  192. v.type_ = BertType.Binary;
  193. v.binaryValue = data;
  194. return v;
  195. }
  196. BertValue bertList(BertValue[] elements){
  197. BertValue v;
  198. v.type_ = BertType.List;
  199. v.listValue = elements;
  200. return v;
  201. }
  202. BertValue bertTuple(BertValue[] elements){
  203. BertValue v;
  204. v.type_ = BertType.Tuple;
  205. v.tupleValue = elements;
  206. return v;
  207. }
  208. BertValue bertMap(BertValue[BertValue] map){
  209. BertValue v;
  210. v.type_ = BertType.Map;
  211. v.mapValue = map;
  212. return v;
  213. }
  214. BertValue bertNil(){
  215. BertValue v;
  216. v.type_ = BertType.Nil;
  217. return v;
  218. }
  219. struct BertDecoder{
  220. ubyte[] data;
  221. size_t pos;
  222. BertValue decode(){
  223. if(pos >= data.length){ throw new Exception("No data to decode"); }
  224. if(data[pos++] != BERT_TAG.VERSION){
  225. throw new Exception("Invalid BERT format: missing version byte");
  226. }
  227. return decodeValue();
  228. }
  229. private BertValue decodeValue(){
  230. if(pos >= data.length){ throw new Exception("Unexpected end of data"); }
  231. ubyte tag = data[pos++];
  232. switch(tag){
  233. case BERT_TAG.SMALL_INT:
  234. if(pos >= data.length){ throw new Exception("Incomplete SMALL_INT"); }
  235. return bertInt(data[pos++]);
  236. case BERT_TAG.INT:
  237. if((pos + 4) > data.length){ throw new Exception("Incomplete INT"); }
  238. int value = bigEndianToNative!int(data[pos..pos+4][0..4]);
  239. pos += 4;
  240. return bertInt(value);
  241. case BERT_TAG.FLOAT:
  242. if((pos + 8) > data.length){ throw new Exception("Incomplete FLOAT"); }
  243. double fvalue = bigEndianToNative!double(data[pos..pos+8][0..8]);
  244. pos += 8;
  245. return bertFloat(fvalue);
  246. case BERT_TAG.ATOM:
  247. if((pos + 2) > data.length){ throw new Exception("Incomplete ATOM length"); }
  248. ushort len = (cast(ushort)data[pos] << 8) | data[pos+1];
  249. pos += 2;
  250. if(pos + len > data.length){ throw new Exception("Incomplete ATOM data"); }
  251. string atom = cast(string)data[pos..pos+len];
  252. pos += len;
  253. return bertAtom(atom);
  254. case BERT_TAG.TUPLE:
  255. if(pos >= data.length){ throw new Exception("Incomplete TUPLE"); }
  256. ubyte arity = data[pos++];
  257. auto elements = new BertValue[arity];
  258. foreach(i; 0..arity){
  259. elements[i] = decodeValue();
  260. }
  261. return bertTuple(elements);
  262. case BERT_TAG.LIST:
  263. if((pos + 4) > data.length){ throw new Exception("Incomplete LIST length"); }
  264. uint len = bigEndianToNative!uint(data[pos..pos+4][0..4]);
  265. pos += 4;
  266. auto elements = new BertValue[len];
  267. foreach(i; 0..len){
  268. elements[i] = decodeValue();
  269. }
  270. if(pos >= data.length || data[pos++] != BERT_TAG.NIL){
  271. throw new Exception("Missing NIL terminator for LIST");
  272. }
  273. return bertList(elements);
  274. case BERT_TAG.BINARY:
  275. if((pos + 4) > data.length){ throw new Exception("Incomplete BINARY length"); }
  276. uint len = bigEndianToNative!uint(data[pos..pos+4][0..4]);
  277. pos += 4;
  278. if((pos + len) > data.length){ throw new Exception("Incomplete BINARY data"); }
  279. auto bin = bertBinary(data[pos..pos+len]);
  280. pos += len;
  281. return bin;
  282. case BERT_TAG.NIL:
  283. return bertNil();
  284. case BERT_TAG.BIGINT:
  285. case BERT_TAG.LARGE_BIG:
  286. return decodeBigInt(tag);
  287. case BERT_TAG.MAP:
  288. if((pos + 4) > data.length){ throw new Exception("Incomplete MAP size"); }
  289. uint size = bigEndianToNative!uint(data[pos..pos+4][0..4]);
  290. pos += 4;
  291. BertValue[BertValue] map;
  292. foreach(i; 0..size){
  293. auto key = decodeValue();
  294. auto value = decodeValue();
  295. map[key] = value;
  296. }
  297. return bertMap(map);
  298. default:
  299. throw new Exception(format("Unknown BERT tag: 0x%x", tag));
  300. }
  301. }
  302. private BertValue decodeBigInt(ubyte tag){
  303. uint n;
  304. ubyte sign;
  305. if(tag == BERT_TAG.BIGINT){
  306. if(pos >= data.length){ throw new Exception("Incomplete BIGINT"); }
  307. n = data[pos++];
  308. }else{
  309. if((pos + 4) > data.length){ throw new Exception("Incomplete LARGE_BIG size"); }
  310. n = bigEndianToNative!uint(data[pos..pos+4][0..4]);
  311. pos += 4;
  312. }
  313. if(pos >= data.length){ throw new Exception("Incomplete BIG sign"); }
  314. sign = data[pos++];
  315. if((pos + n) > data.length){ throw new Exception("Incomplete BIG data"); }
  316. ulong value = 0;
  317. foreach_reverse(i; 0..n){
  318. value = (value << 8) | data[pos++];
  319. }
  320. return bertInt(sign ? (-cast(long)value) : cast(long)value);
  321. }
  322. }