bert.d 9.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391
  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));
  89. }
  90. result.put(">>");
  91. return result.data;
  92. case BertType.Map:
  93. string[] pairs;
  94. foreach(key, value; mapValue){
  95. pairs ~= format("%s: %s", key.toString(), value.toString());
  96. }
  97. return "#{" ~ pairs.join(", ") ~ "}";
  98. case BertType.Nil:
  99. return "[]";
  100. }
  101. }
  102. }
  103. ubyte[] bertEncode(BertValue term){
  104. return [cast(ubyte)BERT_TAG.VERSION] ~ term.encode();
  105. }
  106. ubyte[] encodeInt(long value){
  107. if(value >= 0 && value <= 255){
  108. return [cast(ubyte)BERT_TAG.SMALL_INT, cast(ubyte)value];
  109. }else if(value >= -2147483648 && value <= 2147483647){
  110. ubyte[4] bytes = nativeToBigEndian!int(cast(int)value);
  111. return [cast(ubyte)BERT_TAG.INT] ~ bytes[];
  112. }else{
  113. return encodeBigInt(value);
  114. }
  115. }
  116. ubyte[] encodeBigInt(long value){
  117. bool isNegative = (value < 0);
  118. ulong absValue = isNegative ? (-value) : value;
  119. ubyte[8] temp;
  120. size_t len = 0;
  121. while(absValue > 0){
  122. temp[len++] = cast(ubyte)(absValue & 0xFF);
  123. absValue >>= 8;
  124. }
  125. ubyte[] result = [
  126. cast(ubyte)BERT_TAG.BIGINT,
  127. cast(ubyte)len,
  128. isNegative ? 1 : 0
  129. ];
  130. foreach_reverse(i; 0..len){
  131. result ~= temp[i];
  132. }
  133. return result;
  134. }
  135. ubyte[] encodeFloat(double value){
  136. ubyte[8] bytes = nativeToBigEndian!double(value);
  137. return [cast(ubyte)BERT_TAG.FLOAT] ~ bytes[];
  138. }
  139. ubyte[] encodeAtom(string name){
  140. if(name.length > 255){ throw new Exception("Atom too long"); }
  141. return [
  142. cast(ubyte)BERT_TAG.ATOM,
  143. cast(ubyte)(name.length >> 8),
  144. cast(ubyte)(name.length & 0xFF)
  145. ] ~ cast(ubyte[])name;
  146. }
  147. ubyte[] encodeTuple(BertValue[] elements){
  148. ubyte[] result;
  149. if(elements.length <= 255){
  150. result = [cast(ubyte)BERT_TAG.TUPLE, cast(ubyte)elements.length];
  151. }else{
  152. result = [cast(ubyte)BERT_TAG.LARGE_TUPLE] ~ nativeToBigEndian!uint(cast(uint)elements.length);
  153. }
  154. foreach(elem; elements){
  155. result ~= elem.encode();
  156. }
  157. return result;
  158. }
  159. ubyte[] encodeList(BertValue[] elements){
  160. ubyte[4] lenBytes = nativeToBigEndian!uint(cast(uint)elements.length);
  161. return [cast(ubyte)BERT_TAG.LIST] ~ lenBytes[] ~ elements.map!(e => e.encode()).join() ~ cast(ubyte)BERT_TAG.NIL;
  162. }
  163. ubyte[] encodeBinary(ubyte[] data){
  164. ubyte[4] lenBytes = nativeToBigEndian!uint(cast(uint)data.length);
  165. return [cast(ubyte)BERT_TAG.BINARY] ~ lenBytes[] ~ data;
  166. }
  167. ubyte[] encodeMap(const BertValue[BertValue] map){
  168. ubyte[4] lenBytes = nativeToBigEndian!uint(cast(uint)map.length);
  169. return [cast(ubyte)BERT_TAG.MAP] ~ lenBytes[] ~ map.byPair.map!(p => p.key.encode() ~ p.value.encode()).join();
  170. }
  171. BertValue bertInt(long value){
  172. BertValue v;
  173. v.type_ = BertType.Int;
  174. v.intValue = value;
  175. return v;
  176. }
  177. BertValue bertFloat(double value){
  178. BertValue v;
  179. v.type_ = BertType.Float;
  180. v.floatValue = value;
  181. return v;
  182. }
  183. BertValue bertAtom(string name){
  184. BertValue v;
  185. v.type_ = BertType.Atom;
  186. v.atomValue = name;
  187. return v;
  188. }
  189. BertValue bertBinary(ubyte[] data){
  190. BertValue v;
  191. v.type_ = BertType.Binary;
  192. v.binaryValue = data;
  193. return v;
  194. }
  195. BertValue bertList(BertValue[] elements){
  196. BertValue v;
  197. v.type_ = BertType.List;
  198. v.listValue = elements;
  199. return v;
  200. }
  201. BertValue bertTuple(BertValue[] elements){
  202. BertValue v;
  203. v.type_ = BertType.Tuple;
  204. v.tupleValue = elements;
  205. return v;
  206. }
  207. BertValue bertMap(BertValue[BertValue] map){
  208. BertValue v;
  209. v.type_ = BertType.Map;
  210. v.mapValue = map;
  211. return v;
  212. }
  213. BertValue bertNil(){
  214. BertValue v;
  215. v.type_ = BertType.Nil;
  216. return v;
  217. }
  218. struct BertDecoder{
  219. ubyte[] data;
  220. size_t pos;
  221. BertValue decode(){
  222. if(pos >= data.length){ throw new Exception("No data to decode"); }
  223. if(data[pos++] != BERT_TAG.VERSION){
  224. throw new Exception("Invalid BERT format: missing version byte");
  225. }
  226. return decodeValue();
  227. }
  228. private BertValue decodeValue(){
  229. if(pos >= data.length){ throw new Exception("Unexpected end of data"); }
  230. ubyte tag = data[pos++];
  231. switch(tag){
  232. case BERT_TAG.SMALL_INT:
  233. if(pos >= data.length){ throw new Exception("Incomplete SMALL_INT"); }
  234. return bertInt(data[pos++]);
  235. case BERT_TAG.INT:
  236. if((pos + 4) > data.length){ throw new Exception("Incomplete INT"); }
  237. int value = bigEndianToNative!int(data[pos..pos+4][0..4]);
  238. pos += 4;
  239. return bertInt(value);
  240. case BERT_TAG.FLOAT:
  241. if((pos + 8) > data.length){ throw new Exception("Incomplete FLOAT"); }
  242. double fvalue = bigEndianToNative!double(data[pos..pos+8][0..8]);
  243. pos += 8;
  244. return bertFloat(fvalue);
  245. case BERT_TAG.ATOM:
  246. if((pos + 2) > data.length){ throw new Exception("Incomplete ATOM length"); }
  247. ushort len = (cast(ushort)data[pos] << 8) | data[pos+1];
  248. pos += 2;
  249. if(pos + len > data.length){ throw new Exception("Incomplete ATOM data"); }
  250. string atom = cast(string)data[pos..pos+len];
  251. pos += len;
  252. return bertAtom(atom);
  253. case BERT_TAG.TUPLE:
  254. if(pos >= data.length){ throw new Exception("Incomplete TUPLE"); }
  255. ubyte arity = data[pos++];
  256. auto elements = new BertValue[arity];
  257. foreach(i; 0..arity){
  258. elements[i] = decodeValue();
  259. }
  260. return bertTuple(elements);
  261. case BERT_TAG.LIST:
  262. if((pos + 4) > data.length){ throw new Exception("Incomplete LIST length"); }
  263. uint len = bigEndianToNative!uint(data[pos..pos+4][0..4]);
  264. pos += 4;
  265. auto elements = new BertValue[len];
  266. foreach(i; 0..len){
  267. elements[i] = decodeValue();
  268. }
  269. if(pos >= data.length || data[pos++] != BERT_TAG.NIL){
  270. throw new Exception("Missing NIL terminator for LIST");
  271. }
  272. return bertList(elements);
  273. case BERT_TAG.BINARY:
  274. if((pos + 4) > data.length){ throw new Exception("Incomplete BINARY length"); }
  275. uint len = bigEndianToNative!uint(data[pos..pos+4][0..4]);
  276. pos += 4;
  277. if((pos + len) > data.length){ throw new Exception("Incomplete BINARY data"); }
  278. auto bin = bertBinary(data[pos..pos+len]);
  279. pos += len;
  280. return bin;
  281. case BERT_TAG.NIL:
  282. return bertNil();
  283. case BERT_TAG.BIGINT:
  284. case BERT_TAG.LARGE_BIG:
  285. return decodeBigInt(tag);
  286. case BERT_TAG.MAP:
  287. if((pos + 4) > data.length){ throw new Exception("Incomplete MAP size"); }
  288. uint size = bigEndianToNative!uint(data[pos..pos+4][0..4]);
  289. pos += 4;
  290. BertValue[BertValue] map;
  291. foreach(i; 0..size){
  292. auto key = decodeValue();
  293. auto value = decodeValue();
  294. map[key] = value;
  295. }
  296. return bertMap(map);
  297. default:
  298. throw new Exception(format("Unknown BERT tag: 0x%x", tag));
  299. }
  300. }
  301. private BertValue decodeBigInt(ubyte tag){
  302. uint n;
  303. ubyte sign;
  304. if(tag == BERT_TAG.BIGINT){
  305. if(pos >= data.length){ throw new Exception("Incomplete BIGINT"); }
  306. n = data[pos++];
  307. }else{
  308. if((pos + 4) > data.length){ throw new Exception("Incomplete LARGE_BIG size"); }
  309. n = bigEndianToNative!uint(data[pos..pos+4][0..4]);
  310. pos += 4;
  311. }
  312. if(pos >= data.length){ throw new Exception("Incomplete BIG sign"); }
  313. sign = data[pos++];
  314. if((pos + n) > data.length){ throw new Exception("Incomplete BIG data"); }
  315. ulong value = 0;
  316. foreach_reverse(i; 0..n){
  317. value = (value << 8) | data[pos++];
  318. }
  319. return bertInt(sign ? (-cast(long)value) : cast(long)value);
  320. }
  321. }