691 int[] base64 = isURL ? fromBase64URL : fromBase64; |
691 int[] base64 = isURL ? fromBase64URL : fromBase64; |
692 int dp = 0; |
692 int dp = 0; |
693 int bits = 0; |
693 int bits = 0; |
694 int shiftto = 18; // pos of first byte of 4-byte atom |
694 int shiftto = 18; // pos of first byte of 4-byte atom |
695 while (sp < sl) { |
695 while (sp < sl) { |
|
696 if (bits == 0 && sp + 4 < sl) { // fast path |
|
697 int sl0 = sp + ((sl - sp) & ~0b11); |
|
698 while (sp < sl0) { |
|
699 int b1 = base64[src[sp++] & 0xff]; |
|
700 int b2 = base64[src[sp++] & 0xff]; |
|
701 int b3 = base64[src[sp++] & 0xff]; |
|
702 int b4 = base64[src[sp++] & 0xff]; |
|
703 if ((b1 | b2 | b3 | b4) < 0) { // non base64 byte |
|
704 sp -= 4; |
|
705 break; |
|
706 } |
|
707 int bits0 = b1 << 18 | b2 << 12 | b3 << 6 | b4; |
|
708 dst[dp++] = (byte)(bits0 >> 16); |
|
709 dst[dp++] = (byte)(bits0 >> 8); |
|
710 dst[dp++] = (byte)(bits0); |
|
711 } |
|
712 if (sp >= sl) |
|
713 break; |
|
714 } |
696 int b = src[sp++] & 0xff; |
715 int b = src[sp++] & 0xff; |
697 if ((b = base64[b]) < 0) { |
716 if ((b = base64[b]) < 0) { |
698 if (b == -2) { // padding byte '=' |
717 if (b == -2) { // padding byte '=' |
699 // = shiftto==18 unnecessary padding |
718 // = shiftto==18 unnecessary padding |
700 // x= shiftto==12 a dangling single x |
719 // x= shiftto==12 a dangling single x |
760 private final char[] base64; // byte->base64 mapping |
779 private final char[] base64; // byte->base64 mapping |
761 private final byte[] newline; // line separator, if needed |
780 private final byte[] newline; // line separator, if needed |
762 private final int linemax; |
781 private final int linemax; |
763 private final boolean doPadding;// whether or not to pad |
782 private final boolean doPadding;// whether or not to pad |
764 private int linepos = 0; |
783 private int linepos = 0; |
|
784 private byte[] buf; |
765 |
785 |
766 EncOutputStream(OutputStream os, char[] base64, |
786 EncOutputStream(OutputStream os, char[] base64, |
767 byte[] newline, int linemax, boolean doPadding) { |
787 byte[] newline, int linemax, boolean doPadding) { |
768 super(os); |
788 super(os); |
769 this.base64 = base64; |
789 this.base64 = base64; |
770 this.newline = newline; |
790 this.newline = newline; |
771 this.linemax = linemax; |
791 this.linemax = linemax; |
772 this.doPadding = doPadding; |
792 this.doPadding = doPadding; |
|
793 this.buf = new byte[linemax <= 0 ? 8124 : linemax]; |
773 } |
794 } |
774 |
795 |
775 @Override |
796 @Override |
776 public void write(int b) throws IOException { |
797 public void write(int b) throws IOException { |
777 byte[] buf = new byte[1]; |
798 byte[] buf = new byte[1]; |
804 } |
833 } |
805 } |
834 } |
806 b2 = b[off++] & 0xff; |
835 b2 = b[off++] & 0xff; |
807 len--; |
836 len--; |
808 checkNewline(); |
837 checkNewline(); |
809 out.write(base64[b0 >> 2]); |
838 writeb4(base64[b0 >> 2], |
810 out.write(base64[(b0 << 4) & 0x3f | (b1 >> 4)]); |
839 base64[(b0 << 4) & 0x3f | (b1 >> 4)], |
811 out.write(base64[(b1 << 2) & 0x3f | (b2 >> 6)]); |
840 base64[(b1 << 2) & 0x3f | (b2 >> 6)], |
812 out.write(base64[b2 & 0x3f]); |
841 base64[b2 & 0x3f]); |
813 linepos += 4; |
842 linepos += 4; |
814 } |
843 } |
815 int nBits24 = len / 3; |
844 int nBits24 = len / 3; |
816 leftover = len - (nBits24 * 3); |
845 leftover = len - (nBits24 * 3); |
817 while (nBits24-- > 0) { |
846 |
|
847 while (nBits24 > 0) { |
818 checkNewline(); |
848 checkNewline(); |
819 int bits = (b[off++] & 0xff) << 16 | |
849 int dl = linemax <= 0 ? buf.length : buf.length - linepos; |
820 (b[off++] & 0xff) << 8 | |
850 int sl = off + Math.min(nBits24, dl / 4) * 3; |
821 (b[off++] & 0xff); |
851 int dp = 0; |
822 out.write(base64[(bits >>> 18) & 0x3f]); |
852 for (int sp = off; sp < sl; ) { |
823 out.write(base64[(bits >>> 12) & 0x3f]); |
853 int bits = (b[sp++] & 0xff) << 16 | |
824 out.write(base64[(bits >>> 6) & 0x3f]); |
854 (b[sp++] & 0xff) << 8 | |
825 out.write(base64[bits & 0x3f]); |
855 (b[sp++] & 0xff); |
826 linepos += 4; |
856 buf[dp++] = (byte)base64[(bits >>> 18) & 0x3f]; |
827 } |
857 buf[dp++] = (byte)base64[(bits >>> 12) & 0x3f]; |
|
858 buf[dp++] = (byte)base64[(bits >>> 6) & 0x3f]; |
|
859 buf[dp++] = (byte)base64[bits & 0x3f]; |
|
860 } |
|
861 out.write(buf, 0, dp); |
|
862 off = sl; |
|
863 linepos += dp; |
|
864 nBits24 -= dp / 4; |
|
865 } |
828 if (leftover == 1) { |
866 if (leftover == 1) { |
829 b0 = b[off++] & 0xff; |
867 b0 = b[off++] & 0xff; |
830 } else if (leftover == 2) { |
868 } else if (leftover == 2) { |
831 b0 = b[off++] & 0xff; |
869 b0 = b[off++] & 0xff; |
832 b1 = b[off++] & 0xff; |
870 b1 = b[off++] & 0xff; |
887 @Override |
925 @Override |
888 public int read() throws IOException { |
926 public int read() throws IOException { |
889 return read(sbBuf, 0, 1) == -1 ? -1 : sbBuf[0] & 0xff; |
927 return read(sbBuf, 0, 1) == -1 ? -1 : sbBuf[0] & 0xff; |
890 } |
928 } |
891 |
929 |
|
930 private int eof(byte[] b, int off, int len, int oldOff) |
|
931 throws IOException |
|
932 { |
|
933 eof = true; |
|
934 if (nextin != 18) { |
|
935 if (nextin == 12) |
|
936 throw new IOException("Base64 stream has one un-decoded dangling byte."); |
|
937 // treat ending xx/xxx without padding character legal. |
|
938 // same logic as v == '=' below |
|
939 b[off++] = (byte)(bits >> (16)); |
|
940 if (nextin == 0) { // only one padding byte |
|
941 if (len == 1) { // no enough output space |
|
942 bits >>= 8; // shift to lowest byte |
|
943 nextout = 0; |
|
944 } else { |
|
945 b[off++] = (byte) (bits >> 8); |
|
946 } |
|
947 } |
|
948 } |
|
949 return off == oldOff ? -1 : off - oldOff; |
|
950 } |
|
951 |
|
952 private int padding(byte[] b, int off, int len, int oldOff) |
|
953 throws IOException |
|
954 { |
|
955 // = shiftto==18 unnecessary padding |
|
956 // x= shiftto==12 dangling x, invalid unit |
|
957 // xx= shiftto==6 && missing last '=' |
|
958 // xx=y or last is not '=' |
|
959 if (nextin == 18 || nextin == 12 || |
|
960 nextin == 6 && is.read() != '=') { |
|
961 throw new IOException("Illegal base64 ending sequence:" + nextin); |
|
962 } |
|
963 b[off++] = (byte)(bits >> (16)); |
|
964 if (nextin == 0) { // only one padding byte |
|
965 if (len == 1) { // no enough output space |
|
966 bits >>= 8; // shift to lowest byte |
|
967 nextout = 0; |
|
968 } else { |
|
969 b[off++] = (byte) (bits >> 8); |
|
970 } |
|
971 } |
|
972 eof = true; |
|
973 return off - oldOff; |
|
974 } |
|
975 |
892 @Override |
976 @Override |
893 public int read(byte[] b, int off, int len) throws IOException { |
977 public int read(byte[] b, int off, int len) throws IOException { |
894 if (closed) |
978 if (closed) |
895 throw new IOException("Stream is closed"); |
979 throw new IOException("Stream is closed"); |
896 if (eof && nextout < 0) // eof and no leftover |
980 if (eof && nextout < 0) // eof and no leftover |
897 return -1; |
981 return -1; |
898 if (off < 0 || len < 0 || len > b.length - off) |
982 if (off < 0 || len < 0 || len > b.length - off) |
899 throw new IndexOutOfBoundsException(); |
983 throw new IndexOutOfBoundsException(); |
900 int oldOff = off; |
984 int oldOff = off; |
901 if (nextout >= 0) { // leftover output byte(s) in bits buf |
985 while (nextout >= 0) { // leftover output byte(s) in bits buf |
902 do { |
986 if (len == 0) |
903 if (len == 0) |
987 return off - oldOff; |
904 return off - oldOff; |
988 b[off++] = (byte)(bits >> nextout); |
905 b[off++] = (byte)(bits >> nextout); |
989 len--; |
906 len--; |
990 nextout -= 8; |
907 nextout -= 8; |
991 } |
908 } while (nextout >= 0); |
992 bits = 0; |
909 bits = 0; |
|
910 } |
|
911 while (len > 0) { |
993 while (len > 0) { |
912 int v = is.read(); |
994 int v = is.read(); |
913 if (v == -1) { |
995 if (v == -1) { |
914 eof = true; |
996 return eof(b, off, len, oldOff); |
915 if (nextin != 18) { |
997 } |
916 if (nextin == 12) |
998 if ((v = base64[v]) < 0) { |
917 throw new IOException("Base64 stream has one un-decoded dangling byte."); |
999 if (v == -2) { // padding byte(s) |
918 // treat ending xx/xxx without padding character legal. |
1000 return padding(b, off, len, oldOff); |
919 // same logic as v == '=' below |
1001 } |
920 b[off++] = (byte)(bits >> (16)); |
1002 if (v == -1) { |
921 len--; |
1003 if (!isMIME) |
922 if (nextin == 0) { // only one padding byte |
1004 throw new IOException("Illegal base64 character " + |
923 if (len == 0) { // no enough output space |
1005 Integer.toString(v, 16)); |
924 bits >>= 8; // shift to lowest byte |
1006 continue; // skip if for rfc2045 |
925 nextout = 0; |
1007 } |
926 } else { |
1008 // neve be here |
927 b[off++] = (byte) (bits >> 8); |
|
928 } |
|
929 } |
|
930 } |
|
931 if (off == oldOff) |
|
932 return -1; |
|
933 else |
|
934 return off - oldOff; |
|
935 } |
|
936 if (v == '=') { // padding byte(s) |
|
937 // = shiftto==18 unnecessary padding |
|
938 // x= shiftto==12 dangling x, invalid unit |
|
939 // xx= shiftto==6 && missing last '=' |
|
940 // xx=y or last is not '=' |
|
941 if (nextin == 18 || nextin == 12 || |
|
942 nextin == 6 && is.read() != '=') { |
|
943 throw new IOException("Illegal base64 ending sequence:" + nextin); |
|
944 } |
|
945 b[off++] = (byte)(bits >> (16)); |
|
946 len--; |
|
947 if (nextin == 0) { // only one padding byte |
|
948 if (len == 0) { // no enough output space |
|
949 bits >>= 8; // shift to lowest byte |
|
950 nextout = 0; |
|
951 } else { |
|
952 b[off++] = (byte) (bits >> 8); |
|
953 } |
|
954 } |
|
955 eof = true; |
|
956 break; |
|
957 } |
|
958 if ((v = base64[v]) == -1) { |
|
959 if (isMIME) // skip if for rfc2045 |
|
960 continue; |
|
961 else |
|
962 throw new IOException("Illegal base64 character " + |
|
963 Integer.toString(v, 16)); |
|
964 } |
1009 } |
965 bits |= (v << nextin); |
1010 bits |= (v << nextin); |
966 if (nextin == 0) { |
1011 if (nextin == 0) { |
967 nextin = 18; // clear for next |
1012 nextin = 18; // clear for next in |
968 nextout = 16; |
1013 b[off++] = (byte)(bits >> 16); |
969 while (nextout >= 0) { |
1014 if (len == 1) { |
970 b[off++] = (byte)(bits >> nextout); |
1015 nextout = 8; // 2 bytes left in bits |
971 len--; |
1016 break; |
972 nextout -= 8; |
1017 } |
973 if (len == 0 && nextout >= 0) { // don't clean "bits" |
1018 b[off++] = (byte)(bits >> 8); |
974 return off - oldOff; |
1019 if (len == 2) { |
975 } |
1020 nextout = 0; // 1 byte left in bits |
976 } |
1021 break; |
|
1022 } |
|
1023 b[off++] = (byte)bits; |
|
1024 len -= 3; |
977 bits = 0; |
1025 bits = 0; |
978 } else { |
1026 } else { |
979 nextin -= 6; |
1027 nextin -= 6; |
980 } |
1028 } |
981 } |
1029 } |