001: package gnu.kawa.xml;
002:
003: /** A BinaryObject whose lexical format is base64. */
004:
005: public class Base64Binary extends BinaryObject {
006: public Base64Binary(byte[] data) {
007: this .data = data;
008: }
009:
010: public static final String ENCODING = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=";
011:
012: public static Base64Binary valueOf(String str) {
013: return new Base64Binary(str);
014: }
015:
016: public Base64Binary(String str) {
017: int len = str.length();
018: int blen = 0;
019: for (int i = 0; i < len; i++) {
020: char ch = str.charAt(i);
021: if (!Character.isWhitespace(ch) && ch != '=')
022: blen++;
023: }
024: blen = (3 * blen) / 4;
025: byte[] bytes = new byte[blen];
026:
027: int value = 0;
028: int buffered = 0;
029: int padding = 0;
030: blen = 0;
031: for (int i = 0; i < len; i++) {
032: char ch = str.charAt(i);
033: int v;
034: if (ch >= 'A' && ch <= 'Z')
035: v = ch - 'A';
036: else if (ch >= 'a' && ch <= 'z')
037: v = ch - 'a' + 26;
038: else if (ch >= '0' && ch <= '9')
039: v = ch - '0' + 52;
040: else if (ch == '+')
041: v = 62;
042: else if (ch == '/')
043: v = 63;
044: else if (Character.isWhitespace(ch))
045: continue;
046: else if (ch == '=') {
047: padding++;
048: continue;
049: } else
050: v = -1;
051: if (v < 0 || padding > 0)
052: throw new IllegalArgumentException(
053: "illegal character in base64Binary string at position "
054: + i);
055: value = (value << 6) + v;
056: buffered++;
057: if (buffered == 4) {
058: bytes[blen++] = (byte) (value >> 16);
059: bytes[blen++] = (byte) (value >> 8);
060: bytes[blen++] = (byte) (value);
061: buffered = 0;
062: }
063: /*
064: if (buffered == 4 || ++i == len)
065: {
066: System.err.println("end bl:"+blen+" b:"+buffered+" val:"+Integer.toHexString(value)+" i:"+i);
067: while (--buffered >= 0)
068: {
069: System.err.println("bl:"+blen+" buf:"+buffered);
070: bytes[blen++] = (byte) (value >> (8 * buffered));
071: }
072: bytes[blen++] = (byte) (value >> 16);
073: bytes[blen++] = (byte) (value >> 8);
074: bytes[blen++] = (byte) (value);
075: buffered = 0;
076: }
077: */
078: }
079: if (buffered + padding > 0 ? (buffered + padding != 4
080: || (value & ((1 << padding) - 1)) != 0 || blen + 3
081: - padding != bytes.length) : blen != bytes.length)
082: throw new IllegalArgumentException();
083: switch (padding) {
084: case 1:
085: bytes[blen++] = (byte) (value << 10);
086: bytes[blen++] = (byte) (value >> 2);
087: break;
088: case 2:
089: bytes[blen++] = (byte) (value >> 4);
090: break;
091: }
092: //System.err.println("end bl:"+blen+" b:"+buffered+" val:"+Integer.toHexString(value)+" pad:"+padding);
093: this .data = bytes;
094: }
095:
096: public StringBuffer toString(StringBuffer sbuf) {
097: byte[] bb = data;
098: int len = bb.length;
099: int value = 0;
100: for (int i = 0; i < len;) {
101: byte b = bb[i];
102: value = (value << 8) | (b & 0xFF);
103: i++;
104: if ((i % 3) == 0) {
105: sbuf.append(ENCODING.charAt((value >> 18) & 63));
106: sbuf.append(ENCODING.charAt((value >> 12) & 63));
107: sbuf.append(ENCODING.charAt((value >> 6) & 63));
108: sbuf.append(ENCODING.charAt(value & 63));
109: }
110: }
111: switch (len % 3) {
112: case 1:
113: sbuf.append(ENCODING.charAt((value >> 2) & 63));
114: sbuf.append(ENCODING.charAt((value << 4) & 63));
115: sbuf.append("==");
116: break;
117: case 2:
118: sbuf.append(ENCODING.charAt((value >> 10) & 63));
119: sbuf.append(ENCODING.charAt((value >> 4) & 63));
120: sbuf.append(ENCODING.charAt((value << 2) & 63));
121: sbuf.append('=');
122: break;
123: }
124: return sbuf;
125: }
126:
127: public String toString() {
128: return toString(new StringBuffer()).toString();
129: }
130: }
|