1 /* 2 * hunt-proton: AMQP Protocol library for D programming language. 3 * 4 * Copyright (C) 2018-2019 HuntLabs 5 * 6 * Website: https://www.huntlabs.net/ 7 * 8 * Licensed under the Apache-2.0 License. 9 * 10 */ 11 12 module hunt.proton.codec.impl.DataDecoder; 13 14 15 import hunt.io.ByteBuffer; 16 import hunt.proton.codec.Data; 17 import hunt.Exceptions; 18 import hunt.proton.amqp.UnsignedInteger; 19 import hunt.proton.amqp.UnsignedByte; 20 import hunt.proton.amqp.UnsignedShort; 21 import hunt.proton.amqp.UnsignedLong; 22 import hunt.proton.amqp.Decimal64; 23 import std.datetime.date; 24 import hunt.proton.amqp.Decimal32; 25 import hunt.proton.amqp.Decimal128; 26 import hunt.proton.amqp.Symbol; 27 import hunt.text.Charset; 28 import hunt.time.LocalDateTime; 29 import std.concurrency : initOnce; 30 import std.conv :to ; 31 32 interface TypeConstructor 33 { 34 Data.DataType getType(); 35 36 int size(ByteBuffer b); 37 38 void parse(ByteBuffer b, Data data); 39 } 40 41 42 class DataDecoder 43 { 44 45 //private static Charset ASCII = StandardCharsets.US-ASCII; 46 //private static Charset UTF_8 = StandardCharsets.UTF-8; 47 48 //TypeConstructor[] _constructors = new TypeConstructor[256]; 49 50 51 static TypeConstructor[] _constructors() 52 { 53 __gshared TypeConstructor[] inst; 54 return initOnce!inst(initConstructors()); 55 } 56 // 57 //private static UnsignedInteger[] initConstructor() 58 //{ 59 // 60 //} 61 62 63 static TypeConstructor[] initConstructors() 64 { 65 TypeConstructor[] _constructors = new TypeConstructor[256]; 66 67 _constructors[0x00] = new DescribedTypeConstructor(); 68 69 _constructors[0x40] = new NullConstructor(); 70 _constructors[0x41] = new TrueConstructor(); 71 _constructors[0x42] = new FalseConstructor(); 72 _constructors[0x43] = new UInt0Constructor(); 73 _constructors[0x44] = new ULong0Constructor(); 74 _constructors[0x45] = new EmptyListConstructor(); 75 76 _constructors[0x50] = new UByteConstructor(); 77 _constructors[0x51] = new ByteConstructor(); 78 _constructors[0x52] = new SmallUIntConstructor(); 79 _constructors[0x53] = new SmallULongConstructor(); 80 _constructors[0x54] = new SmallIntConstructor(); 81 _constructors[0x55] = new SmallLongConstructor(); 82 _constructors[0x56] = new BooleanConstructor(); 83 84 _constructors[0x60] = new UShortConstructor(); 85 _constructors[0x61] = new ShortConstructor(); 86 87 _constructors[0x70] = new UIntConstructor(); 88 _constructors[0x71] = new IntConstructor(); 89 _constructors[0x72] = new FloatConstructor(); 90 _constructors[0x73] = new CharConstructor(); 91 _constructors[0x74] = new Decimal32Constructor(); 92 93 _constructors[0x80] = new ULongConstructor(); 94 _constructors[0x81] = new LongConstructor(); 95 _constructors[0x82] = new DoubleConstructor(); 96 _constructors[0x83] = new TimestampConstructor(); 97 _constructors[0x84] = new Decimal64Constructor(); 98 99 _constructors[0x94] = new Decimal128Constructor(); 100 _constructors[0x98] = new UUIDConstructor(); 101 102 _constructors[0xa0] = new SmallBinaryConstructor(); 103 _constructors[0xa1] = new SmallStringConstructor(); 104 _constructors[0xa3] = new SmallSymbolConstructor(); 105 106 _constructors[0xb0] = new BinaryConstructor(); 107 _constructors[0xb1] = new StringConstructor(); 108 _constructors[0xb3] = new SymbolConstructor(); 109 110 _constructors[0xc0] = new SmallListConstructor(); 111 _constructors[0xc1] = new SmallMapConstructor(); 112 113 114 _constructors[0xd0] = new ListConstructor(); 115 _constructors[0xd1] = new MapConstructor(); 116 117 _constructors[0xe0] = new SmallArrayConstructor(); 118 _constructors[0xf0] = new ArrayConstructor(); 119 return _constructors; 120 } 121 122 123 124 125 static int decode(ByteBuffer b, Data data) 126 { 127 if(b.hasRemaining()) 128 { 129 int position = b.position(); 130 TypeConstructor c = readConstructor(b); 131 int size = c.size(b); 132 if(b.remaining() >= size) 133 { 134 c.parse(b, data); 135 return 1+size; 136 } 137 else 138 { 139 b.position(position); 140 return -4; 141 } 142 } 143 return 0; 144 } 145 146 static TypeConstructor readConstructor(ByteBuffer b) 147 { 148 int index = b.get() & 0xff; 149 TypeConstructor tc = _constructors[index]; 150 if(tc is null) 151 { 152 throw new IllegalArgumentException("No constructor for type " ~ to!string(index)); 153 } 154 return tc; 155 } 156 157 158 159 160 161 static void parseChildren(Data data, ByteBuffer buf, int count) 162 { 163 data.enter(); 164 for(int i = 0; i < count; i++) 165 { 166 TypeConstructor c = readConstructor(buf); 167 int size = c.size(buf); 168 int remaining = buf.remaining(); 169 if(size <= remaining) 170 { 171 c.parse(buf, data); 172 } 173 else 174 { 175 throw new IllegalArgumentException("Malformed data"); 176 } 177 178 } 179 data.exit(); 180 } 181 182 183 184 private static void parseArray(Data data, ByteBuffer buf, int count) 185 { 186 byte type = buf.get(); 187 bool isDescribed = type == cast(byte)0x00; 188 int descriptorPosition = buf.position(); 189 if(isDescribed) 190 { 191 TypeConstructor descriptorTc = readConstructor(buf); 192 buf.position(buf.position()+descriptorTc.size(buf)); 193 type = buf.get(); 194 if(type == cast(byte)0x00) 195 { 196 throw new IllegalArgumentException("Malformed array data"); 197 } 198 199 } 200 TypeConstructor tc = _constructors[type&0xff]; 201 202 data.putArray(isDescribed, tc.getType()); 203 data.enter(); 204 if(isDescribed) 205 { 206 int position = buf.position(); 207 buf.position(descriptorPosition); 208 TypeConstructor descriptorTc = readConstructor(buf); 209 descriptorTc.parse(buf,data); 210 buf.position(position); 211 } 212 for(int i = 0; i<count; i++) 213 { 214 tc.parse(buf,data); 215 } 216 217 data.exit(); 218 } 219 220 } 221 222 class NullConstructor : TypeConstructor 223 { 224 override 225 public Data.DataType getType() 226 { 227 return Data.DataType.NULL; 228 } 229 230 override 231 public int size(ByteBuffer b) 232 { 233 return 0; 234 } 235 236 override 237 public void parse(ByteBuffer b, Data data) 238 { 239 data.putNull(); 240 } 241 } 242 243 class TrueConstructor : TypeConstructor 244 { 245 override 246 public Data.DataType getType() 247 { 248 return Data.DataType.BOOL; 249 } 250 251 override 252 public int size(ByteBuffer b) 253 { 254 return 0; 255 } 256 257 override 258 public void parse(ByteBuffer b, Data data) 259 { 260 data.putBoolean(true); 261 } 262 } 263 264 265 class FalseConstructor : TypeConstructor 266 { 267 268 override 269 public Data.DataType getType() 270 { 271 return Data.DataType.BOOL; 272 } 273 274 override 275 public int size(ByteBuffer b) 276 { 277 return 0; 278 } 279 280 override 281 public void parse(ByteBuffer b, Data data) 282 { 283 data.putBoolean(false); 284 } 285 } 286 287 class UInt0Constructor : TypeConstructor 288 { 289 290 override 291 public Data.DataType getType() 292 { 293 return Data.DataType.UINT; 294 } 295 296 override 297 public int size(ByteBuffer b) 298 { 299 return 0; 300 } 301 302 override 303 public void parse(ByteBuffer b, Data data) 304 { 305 data.putUnsignedInteger(UnsignedInteger.ZERO); 306 } 307 } 308 309 class ULong0Constructor : TypeConstructor 310 { 311 312 override 313 public Data.DataType getType() 314 { 315 return Data.DataType.ULONG; 316 } 317 318 override 319 public int size(ByteBuffer b) 320 { 321 return 0; 322 } 323 324 override 325 public void parse(ByteBuffer b, Data data) 326 { 327 data.putUnsignedLong(UnsignedLong.ZERO); 328 } 329 } 330 331 332 class EmptyListConstructor : TypeConstructor 333 { 334 335 override 336 public Data.DataType getType() 337 { 338 return Data.DataType.LIST; 339 } 340 341 override 342 public int size(ByteBuffer b) 343 { 344 return 0; 345 } 346 347 override 348 public void parse(ByteBuffer b, Data data) 349 { 350 data.putList(); 351 } 352 } 353 354 355 abstract class Fixed0SizeConstructor : TypeConstructor 356 { 357 override 358 public int size(ByteBuffer b) 359 { 360 return 0; 361 } 362 } 363 364 abstract class Fixed1SizeConstructor : TypeConstructor 365 { 366 override 367 public int size(ByteBuffer b) 368 { 369 return 1; 370 } 371 } 372 373 abstract class Fixed2SizeConstructor : TypeConstructor 374 { 375 override 376 public int size(ByteBuffer b) 377 { 378 return 2; 379 } 380 } 381 382 abstract class Fixed4SizeConstructor : TypeConstructor 383 { 384 override 385 public int size(ByteBuffer b) 386 { 387 return 4; 388 } 389 } 390 391 abstract class Fixed8SizeConstructor : TypeConstructor 392 { 393 override 394 public int size(ByteBuffer b) 395 { 396 return 8; 397 } 398 } 399 400 abstract class Fixed16SizeConstructor : TypeConstructor 401 { 402 override 403 public int size(ByteBuffer b) 404 { 405 return 16; 406 } 407 } 408 409 class UByteConstructor : Fixed1SizeConstructor 410 { 411 412 public Data.DataType getType() 413 { 414 return Data.DataType.UBYTE; 415 } 416 417 public void parse(ByteBuffer b, Data data) 418 { 419 data.putUnsignedByte(UnsignedByte.valueOf(b.get())); 420 } 421 } 422 423 class ByteConstructor : Fixed1SizeConstructor 424 { 425 426 public Data.DataType getType() 427 { 428 return Data.DataType.BYTE; 429 } 430 431 public void parse(ByteBuffer b, Data data) 432 { 433 data.putByte(b.get()); 434 } 435 } 436 437 class SmallUIntConstructor : Fixed1SizeConstructor 438 { 439 440 public Data.DataType getType() 441 { 442 return Data.DataType.UINT; 443 } 444 445 public void parse(ByteBuffer b, Data data) 446 { 447 data.putUnsignedInteger(UnsignedInteger.valueOf((cast(int) b.get()) & 0xff)); 448 } 449 } 450 451 class SmallIntConstructor : Fixed1SizeConstructor 452 { 453 454 public Data.DataType getType() 455 { 456 return Data.DataType.INT; 457 } 458 459 public void parse(ByteBuffer b, Data data) 460 { 461 data.putInt(b.get()); 462 } 463 } 464 465 class SmallULongConstructor : Fixed1SizeConstructor 466 { 467 468 public Data.DataType getType() 469 { 470 return Data.DataType.ULONG; 471 } 472 473 public void parse(ByteBuffer b, Data data) 474 { 475 data.putUnsignedLong(UnsignedLong.valueOf((cast(int) b.get()) & 0xff)); 476 } 477 } 478 479 class SmallLongConstructor : Fixed1SizeConstructor 480 { 481 482 public Data.DataType getType() 483 { 484 return Data.DataType.LONG; 485 } 486 487 public void parse(ByteBuffer b, Data data) 488 { 489 data.putLong(b.get()); 490 } 491 } 492 493 class BooleanConstructor : Fixed1SizeConstructor 494 { 495 496 public Data.DataType getType() 497 { 498 return Data.DataType.BOOL; 499 } 500 501 public void parse(ByteBuffer b, Data data) 502 { 503 int i = b.get(); 504 if(i != 0 && i != 1) 505 { 506 throw new IllegalArgumentException("Illegal value " ~ to!string(i) ~ " for bool"); 507 } 508 data.putBoolean(i == 1); 509 } 510 } 511 512 class UShortConstructor : Fixed2SizeConstructor 513 { 514 515 public Data.DataType getType() 516 { 517 return Data.DataType.USHORT; 518 } 519 520 public void parse(ByteBuffer b, Data data) 521 { 522 data.putUnsignedShort(UnsignedShort.valueOf(b.getShort())); 523 } 524 } 525 526 class ShortConstructor : Fixed2SizeConstructor 527 { 528 529 public Data.DataType getType() 530 { 531 return Data.DataType.SHORT; 532 } 533 534 public void parse(ByteBuffer b, Data data) 535 { 536 data.putShort(b.getShort()); 537 } 538 } 539 540 class UIntConstructor : Fixed4SizeConstructor 541 { 542 543 public Data.DataType getType() 544 { 545 return Data.DataType.UINT; 546 } 547 548 public void parse(ByteBuffer b, Data data) 549 { 550 data.putUnsignedInteger(UnsignedInteger.valueOf(b.getInt())); 551 } 552 } 553 554 class IntConstructor : Fixed4SizeConstructor 555 { 556 557 public Data.DataType getType() 558 { 559 return Data.DataType.INT; 560 } 561 562 public void parse(ByteBuffer b, Data data) 563 { 564 data.putInt(b.getInt()); 565 } 566 } 567 568 class FloatConstructor : Fixed4SizeConstructor 569 { 570 571 public Data.DataType getType() 572 { 573 return Data.DataType.FLOAT; 574 } 575 576 public void parse(ByteBuffer b, Data data) 577 { 578 data.putFloat(cast(float)b.getInt()); 579 } 580 } 581 582 class CharConstructor : Fixed4SizeConstructor 583 { 584 585 public Data.DataType getType() 586 { 587 return Data.DataType.CHAR; 588 } 589 590 public void parse(ByteBuffer b, Data data) 591 { 592 data.putChar(b.getInt()); 593 } 594 } 595 596 class Decimal32Constructor : Fixed4SizeConstructor 597 { 598 599 public Data.DataType getType() 600 { 601 return Data.DataType.DECIMAL32; 602 } 603 604 public void parse(ByteBuffer b, Data data) 605 { 606 data.putDecimal32(new Decimal32(b.getInt())); 607 } 608 } 609 610 class ULongConstructor : Fixed8SizeConstructor 611 { 612 613 public Data.DataType getType() 614 { 615 return Data.DataType.ULONG; 616 } 617 618 public void parse(ByteBuffer b, Data data) 619 { 620 data.putUnsignedLong(UnsignedLong.valueOf(b.getLong())); 621 } 622 } 623 624 class LongConstructor : Fixed8SizeConstructor 625 { 626 627 public Data.DataType getType() 628 { 629 return Data.DataType.LONG; 630 } 631 632 public void parse(ByteBuffer b, Data data) 633 { 634 data.putLong(b.getLong()); 635 } 636 } 637 638 class DoubleConstructor : Fixed8SizeConstructor 639 { 640 641 public Data.DataType getType() 642 { 643 return Data.DataType.DOUBLE; 644 } 645 646 public void parse(ByteBuffer b, Data data) 647 { 648 data.putDouble(cast(double)b.getLong()); 649 } 650 } 651 652 class TimestampConstructor : Fixed8SizeConstructor 653 { 654 655 public Data.DataType getType() 656 { 657 return Data.DataType.TIMESTAMP; 658 } 659 660 public void parse(ByteBuffer b, Data data) 661 { 662 implementationMissing(false); 663 data.putTimestamp(hunt.time.LocalDateTime.LocalDateTime.ofEpochMilli(b.getLong())); 664 } 665 } 666 667 class Decimal64Constructor : Fixed8SizeConstructor 668 { 669 670 public Data.DataType getType() 671 { 672 return Data.DataType.DECIMAL64; 673 } 674 675 public void parse(ByteBuffer b, Data data) 676 { 677 data.putDecimal64(new Decimal64(b.getLong())); 678 } 679 } 680 681 class Decimal128Constructor : Fixed16SizeConstructor 682 { 683 684 public Data.DataType getType() 685 { 686 return Data.DataType.DECIMAL128; 687 } 688 689 public void parse(ByteBuffer b, Data data) 690 { 691 data.putDecimal128(new Decimal128(b.getLong(), b.getLong())); 692 } 693 } 694 695 class UUIDConstructor : Fixed16SizeConstructor 696 { 697 698 public Data.DataType getType() 699 { 700 return Data.DataType.UUID; 701 } 702 703 public void parse(ByteBuffer b, Data data) 704 { 705 // data.putUUID(new UUID(b.getLong(), b.getLong())); 706 } 707 } 708 709 abstract class SmallVariableConstructor : TypeConstructor 710 { 711 712 public int size(ByteBuffer b) 713 { 714 int position = b.position(); 715 if(b.hasRemaining()) 716 { 717 int size = b.get() & 0xff; 718 b.position(position); 719 720 return size+1; 721 } 722 else 723 { 724 return 1; 725 } 726 } 727 728 } 729 730 abstract class VariableConstructor : TypeConstructor 731 { 732 733 public int size(ByteBuffer b) 734 { 735 int position = b.position(); 736 if(b.remaining()>=4) 737 { 738 int size = b.getInt(); 739 b.position(position); 740 741 return size+4; 742 } 743 else 744 { 745 return 4; 746 } 747 } 748 749 } 750 751 752 class SmallBinaryConstructor : SmallVariableConstructor 753 { 754 755 public Data.DataType getType() 756 { 757 return Data.DataType.BINARY; 758 } 759 760 public void parse(ByteBuffer b, Data data) 761 { 762 int size = b.get() & 0xff; 763 byte[] bytes = new byte[size]; 764 b.get(bytes); 765 data.putBinary(bytes); 766 } 767 } 768 769 class SmallSymbolConstructor : SmallVariableConstructor 770 { 771 772 public Data.DataType getType() 773 { 774 return Data.DataType.SYMBOL; 775 } 776 777 public void parse(ByteBuffer b, Data data) 778 { 779 int size = b.get() & 0xff; 780 byte[] bytes = new byte[size]; 781 b.get(bytes); 782 data.putSymbol(Symbol.valueOf(cast(string)bytes)); 783 } 784 } 785 786 787 class SmallStringConstructor : SmallVariableConstructor 788 { 789 790 public Data.DataType getType() 791 { 792 return Data.DataType.STRING; 793 } 794 795 public void parse(ByteBuffer b, Data data) 796 { 797 int size = b.get() & 0xff; 798 byte[] bytes = new byte[size]; 799 b.get(bytes); 800 data.putString(cast(string)bytes); 801 } 802 } 803 804 class BinaryConstructor : VariableConstructor 805 { 806 public Data.DataType getType() 807 { 808 return Data.DataType.BINARY; 809 } 810 811 public void parse(ByteBuffer b, Data data) 812 { 813 int size = b.getInt(); 814 byte[] bytes = new byte[size]; 815 b.get(bytes); 816 data.putBinary(bytes); 817 } 818 } 819 820 class SymbolConstructor : VariableConstructor 821 { 822 823 public Data.DataType getType() 824 { 825 return Data.DataType.SYMBOL; 826 } 827 828 public void parse(ByteBuffer b, Data data) 829 { 830 int size = b.getInt(); 831 byte[] bytes = new byte[size]; 832 b.get(bytes); 833 data.putSymbol(Symbol.valueOf(cast(string)bytes)); 834 } 835 } 836 837 838 class StringConstructor : VariableConstructor 839 { 840 841 public Data.DataType getType() 842 { 843 return Data.DataType.STRING; 844 } 845 846 public void parse(ByteBuffer b, Data data) 847 { 848 int size = b.getInt(); 849 byte[] bytes = new byte[size]; 850 b.get(bytes); 851 data.putString(cast(string)bytes); 852 } 853 } 854 855 856 class SmallListConstructor : SmallVariableConstructor 857 { 858 859 public Data.DataType getType() 860 { 861 return Data.DataType.LIST; 862 } 863 864 public void parse(ByteBuffer b, Data data) 865 { 866 int size = b.get() & 0xff; 867 ByteBuffer buf = b.slice(); 868 buf.limit(size); 869 b.position(b.position()+size); 870 int count = buf.get() & 0xff; 871 data.putList(); 872 DataDecoder.parseChildren(data, buf, count); 873 } 874 } 875 876 877 class SmallMapConstructor : SmallVariableConstructor 878 { 879 880 public Data.DataType getType() 881 { 882 return Data.DataType.MAP; 883 } 884 885 public void parse(ByteBuffer b, Data data) 886 { 887 int size = b.get() & 0xff; 888 ByteBuffer buf = b.slice(); 889 buf.limit(size); 890 b.position(b.position()+size); 891 int count = buf.get() & 0xff; 892 data.putMap(); 893 DataDecoder.parseChildren(data, buf, count); 894 } 895 } 896 897 898 class ListConstructor : VariableConstructor 899 { 900 public Data.DataType getType() 901 { 902 return Data.DataType.LIST; 903 } 904 public void parse(ByteBuffer b, Data data) 905 { 906 int size = b.getInt(); 907 ByteBuffer buf = b.slice(); 908 buf.limit(size); 909 b.position(b.position()+size); 910 int count = buf.getInt(); 911 data.putList(); 912 DataDecoder.parseChildren(data, buf, count); 913 } 914 } 915 916 917 class MapConstructor : VariableConstructor 918 { 919 920 public Data.DataType getType() 921 { 922 return Data.DataType.MAP; 923 } 924 925 public void parse(ByteBuffer b, Data data) 926 { 927 int size = b.getInt(); 928 ByteBuffer buf = b.slice(); 929 buf.limit(size); 930 b.position(b.position()+size); 931 int count = buf.getInt(); 932 data.putMap(); 933 DataDecoder.parseChildren(data, buf, count); 934 } 935 } 936 class DescribedTypeConstructor : TypeConstructor 937 { 938 939 public Data.DataType getType() 940 { 941 return Data.DataType.DESCRIBED; 942 } 943 public int size(ByteBuffer b) 944 { 945 ByteBuffer buf = b.slice(); 946 if(buf.hasRemaining()) 947 { 948 TypeConstructor c = DataDecoder.readConstructor(buf); 949 int size = c.size(buf); 950 if(buf.remaining()>size) 951 { 952 buf.position(size + 1); 953 c = DataDecoder.readConstructor(buf); 954 return size + 2 + c.size(buf); 955 } 956 else 957 { 958 return size + 2; 959 } 960 } 961 else 962 { 963 return 1; 964 } 965 966 } 967 968 public void parse(ByteBuffer b, Data data) 969 { 970 data.putDescribed(); 971 data.enter(); 972 TypeConstructor c = DataDecoder.readConstructor(b); 973 c.parse(b, data); 974 c = DataDecoder.readConstructor(b); 975 c.parse(b, data); 976 data.exit(); 977 } 978 } 979 980 class SmallArrayConstructor : SmallVariableConstructor 981 { 982 983 public Data.DataType getType() 984 { 985 return Data.DataType.ARRAY; 986 } 987 988 public void parse(ByteBuffer b, Data data) 989 { 990 991 int size = b.get() & 0xff; 992 ByteBuffer buf = b.slice(); 993 buf.limit(size); 994 b.position(b.position()+size); 995 int count = buf.get() & 0xff; 996 DataDecoder.parseArray(data, buf, count); 997 } 998 999 } 1000 1001 class ArrayConstructor : VariableConstructor 1002 { 1003 1004 public Data.DataType getType() 1005 { 1006 return Data.DataType.ARRAY; 1007 } 1008 1009 1010 public void parse(ByteBuffer b, Data data) 1011 { 1012 1013 int size = b.getInt(); 1014 ByteBuffer buf = b.slice(); 1015 buf.limit(size); 1016 b.position(b.position()+size); 1017 int count = buf.getInt(); 1018 DataDecoder.parseArray(data, buf, count); 1019 } 1020 }