| 763 | } |
| 764 | |
| 765 | int str_base64_decode(void *dst_raw, int dst_size, const char *data) |
| 766 | { |
| 767 | unsigned char *dst = (unsigned char *)dst_raw; |
| 768 | int data_len = str_length(data); |
| 769 | |
| 770 | int i; |
| 771 | int o = 0; |
| 772 | |
| 773 | if(data_len % 4 != 0) |
| 774 | { |
| 775 | return -3; |
| 776 | } |
| 777 | if(data_len / 4 * 3 > dst_size) |
| 778 | { |
| 779 | // Output buffer too small. |
| 780 | return -2; |
| 781 | } |
| 782 | for(i = 0; i < data_len; i += 4) |
| 783 | { |
| 784 | int num_output_bytes = 3; |
| 785 | char copy[4]; |
| 786 | int d[4]; |
| 787 | int value; |
| 788 | int b; |
| 789 | mem_copy(copy, data + i, sizeof(copy)); |
| 790 | if(i == data_len - 4) |
| 791 | { |
| 792 | if(copy[3] == '=') |
| 793 | { |
| 794 | copy[3] = 'A'; |
| 795 | num_output_bytes = 2; |
| 796 | if(copy[2] == '=') |
| 797 | { |
| 798 | copy[2] = 'A'; |
| 799 | num_output_bytes = 1; |
| 800 | } |
| 801 | } |
| 802 | } |
| 803 | d[0] = base64_digit_value(copy[0]); |
| 804 | d[1] = base64_digit_value(copy[1]); |
| 805 | d[2] = base64_digit_value(copy[2]); |
| 806 | d[3] = base64_digit_value(copy[3]); |
| 807 | if(d[0] == -1 || d[1] == -1 || d[2] == -1 || d[3] == -1) |
| 808 | { |
| 809 | // Invalid digit. |
| 810 | return -1; |
| 811 | } |
| 812 | value = (d[0] << 18) | (d[1] << 12) | (d[2] << 6) | d[3]; |
| 813 | for(b = 0; b < 3; b++) |
| 814 | { |
| 815 | unsigned char byte_value = (value >> (16 - 8 * b)) & 0xff; |
| 816 | if(b < num_output_bytes) |
| 817 | { |
| 818 | dst[o] = byte_value; |
| 819 | o += 1; |
| 820 | } |
| 821 | else |
| 822 | { |